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" | |
14 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
15 #include "base/time/time.h" | 16 #include "base/time/time.h" |
16 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
17 #include "media/base/video_capture_types.h" | 18 #include "media/base/video_capture_types.h" |
18 #include "media/base/video_frame.h" | 19 #include "media/base/video_frame.h" |
19 #include "media/base/video_frame_metadata.h" | 20 #include "media/base/video_frame_metadata.h" |
20 #include "media/base/video_util.h" | 21 #include "media/base/video_util.h" |
21 #include "ui/gfx/geometry/rect.h" | 22 #include "ui/gfx/geometry/rect.h" |
22 | 23 |
23 namespace media { | 24 namespace media { |
(...skipping 26 matching lines...) Expand all Loading... | |
50 | 51 |
51 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( | 52 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( |
52 VideoCaptureOracle::Event event, | 53 VideoCaptureOracle::Event event, |
53 const gfx::Rect& damage_rect, | 54 const gfx::Rect& damage_rect, |
54 base::TimeTicks event_time, | 55 base::TimeTicks event_time, |
55 scoped_refptr<VideoFrame>* storage, | 56 scoped_refptr<VideoFrame>* storage, |
56 CaptureFrameCallback* callback) { | 57 CaptureFrameCallback* callback) { |
57 // Grab the current time before waiting to acquire the |lock_|. | 58 // Grab the current time before waiting to acquire the |lock_|. |
58 const base::TimeTicks capture_begin_time = base::TimeTicks::Now(); | 59 const base::TimeTicks capture_begin_time = base::TimeTicks::Now(); |
59 | 60 |
60 base::AutoLock guard(lock_); | 61 gfx::Size visible_size; |
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_); | |
61 | 69 |
62 if (!client_) | 70 if (!client_) |
63 return false; // Capture is stopped. | 71 return false; // Capture is stopped. |
64 | 72 |
65 const bool should_capture = | 73 if (!oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time)) { |
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) { | |
99 // This is a normal and acceptable way to drop a frame. We've hit our | 74 // This is a normal and acceptable way to drop a frame. We've hit our |
100 // capture rate limit: for example, the content is animating at 60fps but | 75 // capture rate limit: for example, the content is animating at 60fps but |
101 // we're capturing at 30fps. | 76 // we're capturing at 30fps. |
102 TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited", | 77 TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited", |
103 TRACE_EVENT_SCOPE_THREAD, "trigger", event_name); | 78 TRACE_EVENT_SCOPE_THREAD, "trigger", |
79 VideoCaptureOracle::EventAsString(event)); | |
80 return false; | |
104 } | 81 } |
105 return false; | 82 |
106 } else if (!should_capture && !output_buffer.get()) { | 83 visible_size = oracle_.capture_size(); |
107 // We decided not to capture, but we wouldn't have been able to if we wanted | 84 // TODO(miu): Clients should request exact padding, instead of this |
108 // to because no output buffer was available. | 85 // memory-wasting hack to make frames that are compatible with all HW |
109 TRACE_EVENT_INSTANT1("gpu.capture", "NearlyPipelineLimited", | 86 // encoders. http://crbug.com/555911 |
110 TRACE_EVENT_SCOPE_THREAD, "trigger", event_name); | 87 coded_size.SetSize(base::bits::Align(visible_size.width(), 16), |
111 return false; | 88 base::bits::Align(visible_size.height(), 16)); |
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)); | |
112 } | 130 } |
113 | 131 |
114 const int frame_number = oracle_.RecordCapture(attenuated_utilization); | |
115 TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(), | 132 TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(), |
116 "frame_number", frame_number, "trigger", event_name); | 133 "frame_number", frame_number, "trigger", |
134 VideoCaptureOracle::EventAsString(event)); | |
117 | 135 |
118 DCHECK_EQ(media::PIXEL_STORAGE_CPU, params_.requested_format.pixel_storage); | 136 DCHECK_EQ(media::PIXEL_STORAGE_CPU, params_.requested_format.pixel_storage); |
119 *storage = VideoFrame::WrapExternalSharedMemory( | 137 *storage = VideoFrame::WrapExternalSharedMemory( |
120 params_.requested_format.pixel_format, coded_size, | 138 params_.requested_format.pixel_format, coded_size, |
121 gfx::Rect(visible_size), visible_size, | 139 gfx::Rect(visible_size), visible_size, |
122 static_cast<uint8_t*>(output_buffer->data()), | 140 static_cast<uint8_t*>(output_buffer->data()), |
123 output_buffer->mapped_size(), base::SharedMemory::NULLHandle(), 0u, | 141 output_buffer->mapped_size(), base::SharedMemory::NULLHandle(), 0u, |
124 base::TimeDelta()); | 142 base::TimeDelta()); |
125 if (!(*storage)) | 143 if (!(*storage)) |
126 return false; | 144 return false; |
127 *callback = | 145 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, |
128 base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, frame_number, | 146 frame_number, base::Passed(&output_buffer), |
129 base::Passed(&output_buffer), capture_begin_time, | 147 capture_begin_time, estimated_frame_duration); |
130 oracle_.estimated_frame_duration()); | 148 |
131 return true; | 149 return true; |
132 } | 150 } |
133 | 151 |
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 | |
Irfan
2016/04/06 23:00:21
probably add a comment explaining why the capture
| |
163 capture_callback.Run(frame, refresh_time, true); | |
164 return true; | |
165 } | |
166 | |
134 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { | 167 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const { |
135 base::AutoLock guard(lock_); | 168 base::AutoLock guard(lock_); |
136 return oracle_.capture_size(); | 169 return oracle_.capture_size(); |
137 } | 170 } |
138 | 171 |
139 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { | 172 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) { |
140 base::AutoLock guard(lock_); | 173 base::AutoLock guard(lock_); |
141 VLOG(1) << "Source size changed to " << source_size.ToString(); | 174 VLOG(1) << "Source size changed to " << source_size.ToString(); |
142 oracle_.SetSourceSize(source_size); | 175 oracle_.SetSourceSize(source_size); |
143 } | 176 } |
(...skipping 12 matching lines...) Expand all Loading... | |
156 } | 189 } |
157 | 190 |
158 void ThreadSafeCaptureOracle::DidCaptureFrame( | 191 void ThreadSafeCaptureOracle::DidCaptureFrame( |
159 int frame_number, | 192 int frame_number, |
160 scoped_ptr<VideoCaptureDevice::Client::Buffer> buffer, | 193 scoped_ptr<VideoCaptureDevice::Client::Buffer> buffer, |
161 base::TimeTicks capture_begin_time, | 194 base::TimeTicks capture_begin_time, |
162 base::TimeDelta estimated_frame_duration, | 195 base::TimeDelta estimated_frame_duration, |
163 const scoped_refptr<VideoFrame>& frame, | 196 const scoped_refptr<VideoFrame>& frame, |
164 base::TimeTicks timestamp, | 197 base::TimeTicks timestamp, |
165 bool success) { | 198 bool success) { |
166 base::AutoLock guard(lock_); | |
167 TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(), "success", | 199 TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(), "success", |
168 success, "timestamp", timestamp.ToInternalValue()); | 200 success, "timestamp", timestamp.ToInternalValue()); |
169 | 201 |
202 base::AutoLock guard(lock_); | |
203 | |
170 if (oracle_.CompleteCapture(frame_number, success, ×tamp)) { | 204 if (oracle_.CompleteCapture(frame_number, success, ×tamp)) { |
171 TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded", | 205 TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded", |
172 TRACE_EVENT_SCOPE_THREAD); | 206 TRACE_EVENT_SCOPE_THREAD); |
173 | 207 |
174 if (!client_) | 208 if (!client_) |
175 return; // Capture is stopped. | 209 return; // Capture is stopped. |
176 | 210 |
177 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, | 211 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE, |
178 params_.requested_format.frame_rate); | 212 params_.requested_format.frame_rate); |
179 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, | 213 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, |
(...skipping 18 matching lines...) Expand all Loading... | |
198 // destructor. |metadata| is still valid for read-access at this point. | 232 // destructor. |metadata| is still valid for read-access at this point. |
199 double utilization = -1.0; | 233 double utilization = -1.0; |
200 if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 234 if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
201 &utilization)) { | 235 &utilization)) { |
202 base::AutoLock guard(lock_); | 236 base::AutoLock guard(lock_); |
203 oracle_.RecordConsumerFeedback(frame_number, utilization); | 237 oracle_.RecordConsumerFeedback(frame_number, utilization); |
204 } | 238 } |
205 } | 239 } |
206 | 240 |
207 } // namespace media | 241 } // namespace media |
OLD | NEW |