summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/filters/video_renderer_algorithm.cc48
-rw-r--r--media/filters/video_renderer_algorithm.h19
-rw-r--r--media/filters/video_renderer_algorithm_unittest.cc47
3 files changed, 83 insertions, 31 deletions
diff --git a/media/filters/video_renderer_algorithm.cc b/media/filters/video_renderer_algorithm.cc
index bbbfdb1..a001656 100644
--- a/media/filters/video_renderer_algorithm.cc
+++ b/media/filters/video_renderer_algorithm.cc
@@ -94,7 +94,9 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
base::TimeDelta selected_frame_drift;
// Step 4: Attempt to find the best frame by cadence.
- int frame_to_render = FindBestFrameByCadence();
+ int cadence_overage = 0;
+ int frame_to_render =
+ FindBestFrameByCadence(first_frame_ ? nullptr : &cadence_overage);
if (frame_to_render >= 0) {
selected_frame_drift =
CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render);
@@ -119,6 +121,7 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
}
if (frame_to_render >= 0) {
+ cadence_overage = 0;
selected_frame_drift =
CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render);
}
@@ -128,8 +131,10 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
// least crappy option based on the drift from the deadline. If we're here the
// selection is going to be bad because it means no suitable frame has any
// coverage of the deadline interval.
- if (frame_to_render < 0 || selected_frame_drift > max_acceptable_drift_)
+ if (frame_to_render < 0 || selected_frame_drift > max_acceptable_drift_) {
+ cadence_overage = 0;
frame_to_render = FindBestFrameByDrift(deadline_min, &selected_frame_drift);
+ }
last_render_had_glitch_ = selected_frame_drift > max_acceptable_drift_;
DVLOG_IF(2, last_render_had_glitch_)
@@ -197,7 +202,22 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
// Step 8: Congratulations, the frame selection gauntlet has been passed!
last_frame_index_ = 0;
- ++frame_queue_.front().render_count;
+
+ // If we ended up choosing a frame selected by cadence, carry over the overage
+ // values from the previous frame. Overage is treated as having been
+ // displayed and dropped for each count. If the frame wasn't selected by
+ // cadence, |cadence_overage| will be zero.
+ //
+ // We also don't want to start counting render counts until the first frame
+ // has reached its presentation time; which is considered to be when its
+ // start time is at most |render_interval_| / 2 before |deadline_min|.
+ if (!first_frame_ ||
+ deadline_min >= frame_queue_.front().start_time - render_interval_ / 2) {
+ frame_queue_.front().render_count += cadence_overage + 1;
+ frame_queue_.front().drop_count += cadence_overage;
+ first_frame_ = false;
+ }
+
DCHECK(frame_queue_.front().frame);
return frame_queue_.front().frame;
}
@@ -261,6 +281,7 @@ void VideoRendererAlgorithm::Reset() {
frame_queue_.clear();
cadence_estimator_.Reset();
frame_duration_calculator_.Reset();
+ first_frame_ = true;
// Default to ATSC IS/191 recommendations for maximum acceptable drift before
// we have enough frames to base the maximum on frame duration.
@@ -287,7 +308,7 @@ size_t VideoRendererAlgorithm::EffectiveFramesQueued() const {
}
// Find the first usable frame to start counting from.
- const int start_index = FindBestFrameByCadenceInternal(nullptr);
+ const int start_index = FindBestFrameByCadence(nullptr);
if (start_index < 0)
return 0;
@@ -473,27 +494,12 @@ void VideoRendererAlgorithm::UpdateCadenceForFrames() {
}
}
-int VideoRendererAlgorithm::FindBestFrameByCadence() {
+int VideoRendererAlgorithm::FindBestFrameByCadence(
+ int* remaining_overage) const {
DCHECK(!frame_queue_.empty());
if (!cadence_estimator_.has_cadence())
return -1;
- int remaining_overage = 0;
- const int best_frame =
- FindBestFrameByCadenceInternal(&remaining_overage);
- if (best_frame < 0)
- return -1;
-
- DCHECK_GE(remaining_overage, 0);
-
- // Overage is treated as having been displayed and dropped for each count.
- frame_queue_[best_frame].render_count += remaining_overage;
- frame_queue_[best_frame].drop_count += remaining_overage;
- return best_frame;
-}
-
-int VideoRendererAlgorithm::FindBestFrameByCadenceInternal(
- int* remaining_overage) const {
DCHECK(!frame_queue_.empty());
DCHECK(cadence_estimator_.has_cadence());
const ReadyFrame& current_frame = frame_queue_[last_frame_index_];
diff --git a/media/filters/video_renderer_algorithm.h b/media/filters/video_renderer_algorithm.h
index 8faba28..e730383 100644
--- a/media/filters/video_renderer_algorithm.h
+++ b/media/filters/video_renderer_algorithm.h
@@ -194,20 +194,15 @@ class MEDIA_EXPORT VideoRendererAlgorithm {
// If |cadence_estimator_| has detected a valid cadence, attempts to find the
// next frame which should be rendered. Returns -1 if not enough frames are
- // available for cadence selection or there is no cadence. Will adjust the
- // selected frame's ideal render count if the last rendered frame has been
- // over selected.
- int FindBestFrameByCadence();
-
- // Similar to FindBestFrameByCadence(), but instead of adjusting the last
- // rendered frame's ideal render count in the case of over selection.
- // Optionally returns the number of times a prior frame was over displayed and
- // ate into the returned frames ideal render count via |remaining_overage|.
+ // available for cadence selection or there is no cadence.
+ //
+ // Returns the number of times a prior frame was over displayed and ate into
+ // the returned frames ideal render count via |remaining_overage|.
//
// For example, if we have 2 frames and each has an ideal display count of 3,
// but the first was displayed 4 times, the best frame is the second one, but
// it should only be displayed twice instead of thrice, so it's overage is 1.
- int FindBestFrameByCadenceInternal(int* remaining_overage) const;
+ int FindBestFrameByCadence(int* remaining_overage) const;
// Iterates over |frame_queue_| and finds the frame which covers the most of
// the deadline interval. If multiple frames have coverage of the interval,
@@ -293,6 +288,10 @@ class MEDIA_EXPORT VideoRendererAlgorithm {
// to the queue. Callers are told about these frames during Render().
size_t frames_dropped_during_enqueue_;
+ // When cadence is present, we don't want to start counting against cadence
+ // until the first frame has reached its presentation time.
+ bool first_frame_;
+
DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithm);
};
diff --git a/media/filters/video_renderer_algorithm_unittest.cc b/media/filters/video_renderer_algorithm_unittest.cc
index 11e9ab3..f94ac73 100644
--- a/media/filters/video_renderer_algorithm_unittest.cc
+++ b/media/filters/video_renderer_algorithm_unittest.cc
@@ -1165,4 +1165,51 @@ TEST_F(VideoRendererAlgorithmTest, EnqueueFrames) {
EXPECT_EQ(1u, frames_dropped);
}
+TEST_F(VideoRendererAlgorithmTest, CadenceForFutureFrames) {
+ TickGenerator tg(base::TimeTicks(), 50);
+ time_source_.StartTicking();
+
+ disable_cadence_hysteresis();
+
+ algorithm_.EnqueueFrame(CreateFrame(tg.interval(10)));
+ algorithm_.EnqueueFrame(CreateFrame(tg.interval(11)));
+ algorithm_.EnqueueFrame(CreateFrame(tg.interval(12)));
+ EXPECT_EQ(3u, frames_queued());
+
+ // Call Render() a few times to increment the render count.
+ for (int i = 0; i < 10; ++i) {
+ size_t frames_dropped = 0;
+ scoped_refptr<VideoFrame> rendered_frame =
+ RenderAndStep(&tg, &frames_dropped);
+ EXPECT_EQ(3u, frames_queued());
+ EXPECT_EQ(tg.interval(10), rendered_frame->timestamp());
+ ASSERT_TRUE(is_using_cadence());
+ }
+
+ // Add some noise to the tick generator so it our first frame
+ // doesn't line up evenly on a deadline.
+ tg.Reset(tg.current() + base::TimeDelta::FromMilliseconds(5));
+
+ // We're now at the first frame, cadence should be one, so
+ // it should only be displayed once.
+ size_t frames_dropped = 0;
+ scoped_refptr<VideoFrame> rendered_frame =
+ RenderAndStep(&tg, &frames_dropped);
+ EXPECT_EQ(3u, frames_queued());
+ EXPECT_EQ(tg.interval(10), rendered_frame->timestamp());
+ ASSERT_TRUE(is_using_cadence());
+
+ // Then the next frame should be displayed.
+ rendered_frame = RenderAndStep(&tg, &frames_dropped);
+ EXPECT_EQ(2u, frames_queued());
+ EXPECT_EQ(tg.interval(11), rendered_frame->timestamp());
+ ASSERT_TRUE(is_using_cadence());
+
+ // Finally the last frame.
+ rendered_frame = RenderAndStep(&tg, &frames_dropped);
+ EXPECT_EQ(1u, frames_queued());
+ EXPECT_EQ(tg.interval(12), rendered_frame->timestamp());
+ ASSERT_TRUE(is_using_cadence());
+}
+
} // namespace media