OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/capture/content/thread_safe_capture_oracle.h" | 5 #include "media/capture/content/thread_safe_capture_oracle.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bits.h" | 11 #include "base/bits.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/numerics/safe_conversions.h" | |
15 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
16 #include "base/time/time.h" | 15 #include "base/time/time.h" |
17 #include "base/trace_event/trace_event.h" | 16 #include "base/trace_event/trace_event.h" |
18 #include "media/base/video_capture_types.h" | 17 #include "media/base/video_capture_types.h" |
19 #include "media/base/video_frame.h" | 18 #include "media/base/video_frame.h" |
20 #include "media/base/video_frame_metadata.h" | 19 #include "media/base/video_frame_metadata.h" |
21 #include "media/base/video_util.h" | 20 #include "media/base/video_util.h" |
22 #include "ui/gfx/geometry/rect.h" | 21 #include "ui/gfx/geometry/rect.h" |
23 | 22 |
24 namespace media { | 23 namespace media { |
(...skipping 26 matching lines...) Expand all Loading... |
51 | 50 |
52 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( | 51 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( |
53 VideoCaptureOracle::Event event, | 52 VideoCaptureOracle::Event event, |
54 const gfx::Rect& damage_rect, | 53 const gfx::Rect& damage_rect, |
55 base::TimeTicks event_time, | 54 base::TimeTicks event_time, |
56 scoped_refptr<VideoFrame>* storage, | 55 scoped_refptr<VideoFrame>* storage, |
57 CaptureFrameCallback* callback) { | 56 CaptureFrameCallback* callback) { |
58 // Grab the current time before waiting to acquire the |lock_|. | 57 // Grab the current time before waiting to acquire the |lock_|. |
59 const base::TimeTicks capture_begin_time = base::TimeTicks::Now(); | 58 const base::TimeTicks capture_begin_time = base::TimeTicks::Now(); |
60 | 59 |
61 gfx::Size visible_size; | 60 base::AutoLock guard(lock_); |
62 gfx::Size coded_size; | |
63 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer; | |
64 double attenuated_utilization; | |
65 int frame_number; | |
66 base::TimeDelta estimated_frame_duration; | |
67 { | |
68 base::AutoLock guard(lock_); | |
69 | 61 |
70 if (!client_) | 62 if (!client_) |
71 return false; // Capture is stopped. | 63 return false; // Capture is stopped. |
72 | 64 |
73 if (!oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time)) { | 65 const bool should_capture = |
| 66 oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time); |
| 67 const gfx::Size visible_size = oracle_.capture_size(); |
| 68 // TODO(miu): Clients should request exact padding, instead of this |
| 69 // memory-wasting hack to make frames that are compatible with all HW |
| 70 // encoders. http://crbug.com/555911 |
| 71 const gfx::Size coded_size(base::bits::Align(visible_size.width(), 16), |
| 72 base::bits::Align(visible_size.height(), 16)); |
| 73 |
| 74 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( |
| 75 client_->ReserveOutputBuffer(coded_size, |
| 76 params_.requested_format.pixel_format, |
| 77 params_.requested_format.pixel_storage)); |
| 78 // Get the current buffer pool utilization and attenuate it: The utilization |
| 79 // reported to the oracle is in terms of a maximum sustainable amount (not the |
| 80 // absolute maximum). |
| 81 const double attenuated_utilization = |
| 82 client_->GetBufferPoolUtilization() * |
| 83 (100.0 / kTargetMaxPoolUtilizationPercent); |
| 84 |
| 85 const char* event_name = |
| 86 (event == VideoCaptureOracle::kTimerPoll |
| 87 ? "poll" |
| 88 : (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" |
| 89 : "unknown")); |
| 90 |
| 91 // Consider the various reasons not to initiate a capture. |
| 92 if (should_capture && !output_buffer.get()) { |
| 93 TRACE_EVENT_INSTANT1("gpu.capture", "PipelineLimited", |
| 94 TRACE_EVENT_SCOPE_THREAD, "trigger", event_name); |
| 95 oracle_.RecordWillNotCapture(attenuated_utilization); |
| 96 return false; |
| 97 } else if (!should_capture && output_buffer.get()) { |
| 98 if (event == VideoCaptureOracle::kCompositorUpdate) { |
74 // This is a normal and acceptable way to drop a frame. We've hit our | 99 // This is a normal and acceptable way to drop a frame. We've hit our |
75 // capture rate limit: for example, the content is animating at 60fps but | 100 // capture rate limit: for example, the content is animating at 60fps but |
76 // we're capturing at 30fps. | 101 // we're capturing at 30fps. |
77 TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited", | 102 TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited", |
78 TRACE_EVENT_SCOPE_THREAD, "trigger", | 103 TRACE_EVENT_SCOPE_THREAD, "trigger", event_name); |
79 VideoCaptureOracle::EventAsString(event)); | |
80 return false; | |
81 } | 104 } |
82 | 105 return false; |
83 visible_size = oracle_.capture_size(); | 106 } else if (!should_capture && !output_buffer.get()) { |
84 // TODO(miu): Clients should request exact padding, instead of this | 107 // We decided not to capture, but we wouldn't have been able to if we wanted |
85 // memory-wasting hack to make frames that are compatible with all HW | 108 // to because no output buffer was available. |
86 // encoders. http://crbug.com/555911 | 109 TRACE_EVENT_INSTANT1("gpu.capture", "NearlyPipelineLimited", |
87 coded_size.SetSize(base::bits::Align(visible_size.width(), 16), | 110 TRACE_EVENT_SCOPE_THREAD, "trigger", event_name); |
88 base::bits::Align(visible_size.height(), 16)); | 111 return false; |
89 | |
90 if (event == VideoCaptureOracle::kPassiveRefreshRequest) { | |
91 output_buffer = client_->ResurrectLastOutputBuffer( | |
92 coded_size, params_.requested_format.pixel_format, | |
93 params_.requested_format.pixel_storage); | |
94 if (!output_buffer) { | |
95 TRACE_EVENT_INSTANT0("gpu.capture", "ResurrectionFailed", | |
96 TRACE_EVENT_SCOPE_THREAD); | |
97 return false; | |
98 } | |
99 } else { | |
100 output_buffer = client_->ReserveOutputBuffer( | |
101 coded_size, params_.requested_format.pixel_format, | |
102 params_.requested_format.pixel_storage); | |
103 } | |
104 | |
105 // Get the current buffer pool utilization and attenuate it: The utilization | |
106 // reported to the oracle is in terms of a maximum sustainable amount (not | |
107 // the absolute maximum). | |
108 attenuated_utilization = client_->GetBufferPoolUtilization() * | |
109 (100.0 / kTargetMaxPoolUtilizationPercent); | |
110 | |
111 if (!output_buffer) { | |
112 TRACE_EVENT_INSTANT2( | |
113 "gpu.capture", "PipelineLimited", TRACE_EVENT_SCOPE_THREAD, "trigger", | |
114 VideoCaptureOracle::EventAsString(event), "atten_util_percent", | |
115 base::saturated_cast<int>(attenuated_utilization * 100.0 + 0.5)); | |
116 oracle_.RecordWillNotCapture(attenuated_utilization); | |
117 return false; | |
118 } | |
119 | |
120 frame_number = oracle_.RecordCapture(attenuated_utilization); | |
121 estimated_frame_duration = oracle_.estimated_frame_duration(); | |
122 } // End of critical section. | |
123 | |
124 if (attenuated_utilization >= 1.0) { | |
125 TRACE_EVENT_INSTANT2( | |
126 "gpu.capture", "NearlyPipelineLimited", TRACE_EVENT_SCOPE_THREAD, | |
127 "trigger", VideoCaptureOracle::EventAsString(event), | |
128 "atten_util_percent", | |
129 base::saturated_cast<int>(attenuated_utilization * 100.0 + 0.5)); | |
130 } | 112 } |
131 | 113 |
| 114 const int frame_number = oracle_.RecordCapture(attenuated_utilization); |
132 TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(), | 115 TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(), |
133 "frame_number", frame_number, "trigger", | 116 "frame_number", frame_number, "trigger", event_name); |
134 VideoCaptureOracle::EventAsString(event)); | |
135 | 117 |
136 DCHECK_EQ(media::PIXEL_STORAGE_CPU, params_.requested_format.pixel_storage); | 118 DCHECK_EQ(media::PIXEL_STORAGE_CPU, params_.requested_format.pixel_storage); |
137 *storage = VideoFrame::WrapExternalSharedMemory( | 119 *storage = VideoFrame::WrapExternalSharedMemory( |
138 params_.requested_format.pixel_format, coded_size, | 120 params_.requested_format.pixel_format, coded_size, |
139 gfx::Rect(visible_size), visible_size, | 121 gfx::Rect(visible_size), visible_size, |
140 static_cast<uint8_t*>(output_buffer->data()), | 122 static_cast<uint8_t*>(output_buffer->data()), |
141 output_buffer->mapped_size(), base::SharedMemory::NULLHandle(), 0u, | 123 output_buffer->mapped_size(), base::SharedMemory::NULLHandle(), 0u, |
142 base::TimeDelta()); | 124 base::TimeDelta()); |
143 if (!(*storage)) | 125 if (!(*storage)) |
144 return false; | 126 return false; |
145 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, | 127 *callback = |
146 frame_number, base::Passed(&output_buffer), | 128 base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, frame_number, |
147 capture_begin_time, estimated_frame_duration); | 129 base::Passed(&output_buffer), capture_begin_time, |
148 | 130 oracle_.estimated_frame_duration()); |
149 return true; | 131 return true; |
150 } | 132 } |
151 | 133 |
152 bool ThreadSafeCaptureOracle::AttemptPassiveRefresh() { | |
153 const base::TimeTicks refresh_time = base::TimeTicks::Now(); | |
154 | |
155 scoped_refptr<VideoFrame> frame; | |
156 CaptureFrameCallback capture_callback; | |
157 if (!ObserveEventAndDecideCapture(VideoCaptureOracle::kPassiveRefreshRequest, | |
158 gfx::Rect(), refresh_time, &frame, | |
159 &capture_callback)) { | |
160 return false; | |
161 } | |
162 | |
163 capture_callback.Run(frame, refresh_time, true); | |
164 return true; | |
165 } | |
166 | |
167 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { | 134 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { |
168 base::AutoLock guard(lock_); | 135 base::AutoLock guard(lock_); |
169 return oracle_.capture_size(); | 136 return oracle_.capture_size(); |
170 } | 137 } |
171 | 138 |
172 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { | 139 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { |
173 base::AutoLock guard(lock_); | 140 base::AutoLock guard(lock_); |
174 VLOG(1) << "Source size changed to " << source_size.ToString(); | 141 VLOG(1) << "Source size changed to " << source_size.ToString(); |
175 oracle_.SetSourceSize(source_size); | 142 oracle_.SetSourceSize(source_size); |
176 } | 143 } |
(...skipping 12 matching lines...) Expand all Loading... |
189 } | 156 } |
190 | 157 |
191 void ThreadSafeCaptureOracle::DidCaptureFrame( | 158 void ThreadSafeCaptureOracle::DidCaptureFrame( |
192 int frame_number, | 159 int frame_number, |
193 scoped_ptr<VideoCaptureDevice::Client::Buffer> buffer, | 160 scoped_ptr<VideoCaptureDevice::Client::Buffer> buffer, |
194 base::TimeTicks capture_begin_time, | 161 base::TimeTicks capture_begin_time, |
195 base::TimeDelta estimated_frame_duration, | 162 base::TimeDelta estimated_frame_duration, |
196 const scoped_refptr<VideoFrame>& frame, | 163 const scoped_refptr<VideoFrame>& frame, |
197 base::TimeTicks timestamp, | 164 base::TimeTicks timestamp, |
198 bool success) { | 165 bool success) { |
| 166 base::AutoLock guard(lock_); |
199 TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(), "success", | 167 TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(), "success", |
200 success, "timestamp", timestamp.ToInternalValue()); | 168 success, "timestamp", timestamp.ToInternalValue()); |
201 | 169 |
202 base::AutoLock guard(lock_); | |
203 | |
204 if (oracle_.CompleteCapture(frame_number, success, ×tamp)) { | 170 if (oracle_.CompleteCapture(frame_number, success, ×tamp)) { |
205 TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded", | 171 TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded", |
206 TRACE_EVENT_SCOPE_THREAD); | 172 TRACE_EVENT_SCOPE_THREAD); |
207 | 173 |
208 if (!client_) | 174 if (!client_) |
209 return; // Capture is stopped. | 175 return; // Capture is stopped. |
210 | 176 |
211 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, | 177 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, |
212 params_.requested_format.frame_rate); | 178 params_.requested_format.frame_rate); |
213 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, | 179 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, |
(...skipping 18 matching lines...) Expand all Loading... |
232 // destructor. |metadata| is still valid for read-access at this point. | 198 // destructor. |metadata| is still valid for read-access at this point. |
233 double utilization = -1.0; | 199 double utilization = -1.0; |
234 if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 200 if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
235 &utilization)) { | 201 &utilization)) { |
236 base::AutoLock guard(lock_); | 202 base::AutoLock guard(lock_); |
237 oracle_.RecordConsumerFeedback(frame_number, utilization); | 203 oracle_.RecordConsumerFeedback(frame_number, utilization); |
238 } | 204 } |
239 } | 205 } |
240 | 206 |
241 } // namespace media | 207 } // namespace media |
OLD | NEW |