third_party: Add OWNERS for re2 library.
[chromium-blink-merge.git] / media / capture / video_capture_oracle.cc
blob0d88397c2d5ff490a713944af34fa3d24932449b
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/capture/video_capture_oracle.h"
7 #include <algorithm>
9 #include "base/format_macros.h"
10 #include "base/strings/stringprintf.h"
12 namespace media {
14 namespace {
16 // This value controls how many redundant, timer-base captures occur when the
17 // content is static. Redundantly capturing the same frame allows iterative
18 // quality enhancement, and also allows the buffer to fill in "buffered mode".
20 // TODO(nick): Controlling this here is a hack and a layering violation, since
21 // it's a strategy specific to the WebRTC consumer, and probably just papers
22 // over some frame dropping and quality bugs. It should either be controlled at
23 // a higher level, or else redundant frame generation should be pushed down
24 // further into the WebRTC encoding stack.
25 const int kNumRedundantCapturesOfStaticContent = 200;
27 // Given the amount of time between frames, compare to the expected amount of
28 // time between frames at |frame_rate| and return the fractional difference.
29 double FractionFromExpectedFrameRate(base::TimeDelta delta, int frame_rate) {
30 DCHECK_GT(frame_rate, 0);
31 const base::TimeDelta expected_delta =
32 base::TimeDelta::FromSeconds(1) / frame_rate;
33 return (delta - expected_delta).InMillisecondsF() /
34 expected_delta.InMillisecondsF();
37 } // anonymous namespace
39 VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta min_capture_period)
40 : next_frame_number_(0),
41 last_successfully_delivered_frame_number_(-1),
42 num_frames_pending_(0),
43 smoothing_sampler_(min_capture_period,
44 kNumRedundantCapturesOfStaticContent),
45 content_sampler_(min_capture_period) {
48 VideoCaptureOracle::~VideoCaptureOracle() {}
50 bool VideoCaptureOracle::ObserveEventAndDecideCapture(
51 Event event,
52 const gfx::Rect& damage_rect,
53 base::TimeTicks event_time) {
54 DCHECK_GE(event, 0);
55 DCHECK_LT(event, kNumEvents);
56 if (event_time < last_event_time_[event]) {
57 LOG(WARNING) << "Event time is not monotonically non-decreasing. "
58 << "Deciding not to capture this frame.";
59 return false;
61 last_event_time_[event] = event_time;
63 bool should_sample = false;
64 duration_of_next_frame_ = base::TimeDelta();
65 switch (event) {
66 case kCompositorUpdate:
67 smoothing_sampler_.ConsiderPresentationEvent(event_time);
68 content_sampler_.ConsiderPresentationEvent(damage_rect, event_time);
69 if (content_sampler_.HasProposal()) {
70 should_sample = content_sampler_.ShouldSample();
71 if (should_sample) {
72 event_time = content_sampler_.frame_timestamp();
73 duration_of_next_frame_ = content_sampler_.sampling_period();
75 } else {
76 should_sample = smoothing_sampler_.ShouldSample();
77 if (should_sample)
78 duration_of_next_frame_ = smoothing_sampler_.min_capture_period();
80 break;
81 case kTimerPoll:
82 // While the timer is firing, only allow a sampling if there are none
83 // currently in-progress.
84 if (num_frames_pending_ == 0) {
85 should_sample = smoothing_sampler_.IsOverdueForSamplingAt(event_time);
86 if (should_sample)
87 duration_of_next_frame_ = smoothing_sampler_.min_capture_period();
89 break;
90 case kNumEvents:
91 NOTREACHED();
92 break;
95 SetFrameTimestamp(next_frame_number_, event_time);
96 return should_sample;
99 int VideoCaptureOracle::RecordCapture() {
100 smoothing_sampler_.RecordSample();
101 content_sampler_.RecordSample(GetFrameTimestamp(next_frame_number_));
102 num_frames_pending_++;
103 return next_frame_number_++;
106 bool VideoCaptureOracle::CompleteCapture(int frame_number,
107 bool capture_was_successful,
108 base::TimeTicks* frame_timestamp) {
109 num_frames_pending_--;
111 // Drop frame if previously delivered frame number is higher.
112 if (last_successfully_delivered_frame_number_ > frame_number) {
113 LOG_IF(WARNING, capture_was_successful)
114 << "Out of order frame delivery detected (have #" << frame_number
115 << ", last was #" << last_successfully_delivered_frame_number_
116 << "). Dropping frame.";
117 return false;
120 if (!capture_was_successful) {
121 VLOG(2) << "Capture of frame #" << frame_number << " was not successful.";
122 return false;
125 DCHECK_NE(last_successfully_delivered_frame_number_, frame_number);
126 last_successfully_delivered_frame_number_ = frame_number;
128 *frame_timestamp = GetFrameTimestamp(frame_number);
130 // If enabled, log a measurement of how this frame timestamp has incremented
131 // in relation to an ideal increment.
132 if (VLOG_IS_ON(2) && frame_number > 0) {
133 const base::TimeDelta delta =
134 *frame_timestamp - GetFrameTimestamp(frame_number - 1);
135 if (content_sampler_.HasProposal()) {
136 const double estimated_frame_rate =
137 1000000.0 / content_sampler_.detected_period().InMicroseconds();
138 const int rounded_frame_rate =
139 static_cast<int>(estimated_frame_rate + 0.5);
140 VLOG(2) << base::StringPrintf(
141 "Captured #%d: delta=%" PRId64 " usec"
142 ", now locked into {%s}, %+0.1f%% slower than %d FPS",
143 frame_number,
144 delta.InMicroseconds(),
145 content_sampler_.detected_region().ToString().c_str(),
146 100.0 * FractionFromExpectedFrameRate(delta, rounded_frame_rate),
147 rounded_frame_rate);
148 } else {
149 VLOG(2) << base::StringPrintf(
150 "Captured #%d: delta=%" PRId64 " usec"
151 ", d/30fps=%+0.1f%%, d/25fps=%+0.1f%%, d/24fps=%+0.1f%%",
152 frame_number,
153 delta.InMicroseconds(),
154 100.0 * FractionFromExpectedFrameRate(delta, 30),
155 100.0 * FractionFromExpectedFrameRate(delta, 25),
156 100.0 * FractionFromExpectedFrameRate(delta, 24));
160 return !frame_timestamp->is_null();
163 base::TimeTicks VideoCaptureOracle::GetFrameTimestamp(int frame_number) const {
164 DCHECK_LE(frame_number, next_frame_number_);
165 DCHECK_LT(next_frame_number_ - frame_number, kMaxFrameTimestamps);
166 return frame_timestamps_[frame_number % kMaxFrameTimestamps];
169 void VideoCaptureOracle::SetFrameTimestamp(int frame_number,
170 base::TimeTicks timestamp) {
171 frame_timestamps_[frame_number % kMaxFrameTimestamps] = timestamp;
174 } // namespace media