Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: media/capture/content/thread_safe_capture_oracle.cc

Issue 2143903003: [WIP] Move media/capture to device/capture (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/capture/content/thread_safe_capture_oracle.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/bits.h"
14 #include "base/logging.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/synchronization/lock.h"
17 #include "base/time/time.h"
18 #include "base/trace_event/trace_event.h"
19 #include "media/base/video_capture_types.h"
20 #include "media/base/video_frame.h"
21 #include "media/base/video_frame_metadata.h"
22 #include "media/base/video_util.h"
23 #include "ui/gfx/geometry/rect.h"
24
25 namespace media {
26
27 namespace {
28
29 // The target maximum amount of the buffer pool to utilize. Actual buffer pool
30 // utilization is attenuated by this amount before being reported to the
31 // VideoCaptureOracle. This value takes into account the maximum number of
32 // buffer pool buffers and a desired safety margin.
33 const int kTargetMaxPoolUtilizationPercent = 60;
34
35 } // namespace
36
37 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
38 std::unique_ptr<VideoCaptureDevice::Client> client,
39 const VideoCaptureParams& params,
40 bool enable_auto_throttling)
41 : client_(std::move(client)),
42 oracle_(base::TimeDelta::FromMicroseconds(static_cast<int64_t>(
43 1000000.0 / params.requested_format.frame_rate +
44 0.5 /* to round to nearest int */)),
45 params.requested_format.frame_size,
46 params.resolution_change_policy,
47 enable_auto_throttling),
48 params_(params) {}
49
50 ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {
51 }
52
53 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
54 VideoCaptureOracle::Event event,
55 const gfx::Rect& damage_rect,
56 base::TimeTicks event_time,
57 scoped_refptr<VideoFrame>* storage,
58 CaptureFrameCallback* callback) {
59 // Grab the current time before waiting to acquire the |lock_|.
60 const base::TimeTicks capture_begin_time = base::TimeTicks::Now();
61
62 gfx::Size visible_size;
63 gfx::Size coded_size;
64 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer;
65 double attenuated_utilization;
66 int frame_number;
67 base::TimeDelta estimated_frame_duration;
68 {
69 base::AutoLock guard(lock_);
70
71 if (!client_)
72 return false; // Capture is stopped.
73
74 if (!oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time)) {
75 // This is a normal and acceptable way to drop a frame. We've hit our
76 // capture rate limit: for example, the content is animating at 60fps but
77 // we're capturing at 30fps.
78 TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited",
79 TRACE_EVENT_SCOPE_THREAD, "trigger",
80 VideoCaptureOracle::EventAsString(event));
81 return false;
82 }
83
84 visible_size = oracle_.capture_size();
85 // TODO(miu): Clients should request exact padding, instead of this
86 // memory-wasting hack to make frames that are compatible with all HW
87 // encoders. http://crbug.com/555911
88 coded_size.SetSize(base::bits::Align(visible_size.width(), 16),
89 base::bits::Align(visible_size.height(), 16));
90
91 if (event == VideoCaptureOracle::kPassiveRefreshRequest) {
92 output_buffer = client_->ResurrectLastOutputBuffer(
93 coded_size, params_.requested_format.pixel_format,
94 params_.requested_format.pixel_storage);
95 if (!output_buffer) {
96 TRACE_EVENT_INSTANT0("gpu.capture", "ResurrectionFailed",
97 TRACE_EVENT_SCOPE_THREAD);
98 return false;
99 }
100 } else {
101 output_buffer = client_->ReserveOutputBuffer(
102 coded_size, params_.requested_format.pixel_format,
103 params_.requested_format.pixel_storage);
104 }
105
106 // Get the current buffer pool utilization and attenuate it: The utilization
107 // reported to the oracle is in terms of a maximum sustainable amount (not
108 // the absolute maximum).
109 attenuated_utilization = client_->GetBufferPoolUtilization() *
110 (100.0 / kTargetMaxPoolUtilizationPercent);
111
112 if (!output_buffer) {
113 TRACE_EVENT_INSTANT2(
114 "gpu.capture", "PipelineLimited", TRACE_EVENT_SCOPE_THREAD, "trigger",
115 VideoCaptureOracle::EventAsString(event), "atten_util_percent",
116 base::saturated_cast<int>(attenuated_utilization * 100.0 + 0.5));
117 oracle_.RecordWillNotCapture(attenuated_utilization);
118 return false;
119 }
120
121 frame_number = oracle_.RecordCapture(attenuated_utilization);
122 estimated_frame_duration = oracle_.estimated_frame_duration();
123 } // End of critical section.
124
125 if (attenuated_utilization >= 1.0) {
126 TRACE_EVENT_INSTANT2(
127 "gpu.capture", "NearlyPipelineLimited", TRACE_EVENT_SCOPE_THREAD,
128 "trigger", VideoCaptureOracle::EventAsString(event),
129 "atten_util_percent",
130 base::saturated_cast<int>(attenuated_utilization * 100.0 + 0.5));
131 }
132
133 TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(),
134 "frame_number", frame_number, "trigger",
135 VideoCaptureOracle::EventAsString(event));
136
137 DCHECK_EQ(media::PIXEL_STORAGE_CPU, params_.requested_format.pixel_storage);
138 *storage = VideoFrame::WrapExternalSharedMemory(
139 params_.requested_format.pixel_format, coded_size,
140 gfx::Rect(visible_size), visible_size,
141 static_cast<uint8_t*>(output_buffer->data()),
142 output_buffer->mapped_size(), base::SharedMemory::NULLHandle(), 0u,
143 base::TimeDelta());
144 // If creating the VideoFrame wrapper failed, call DidCaptureFrame() with
145 // !success to execute the required post-capture steps (tracing, notification
146 // of failure to VideoCaptureOracle, etc.).
147 if (!(*storage)) {
148 DidCaptureFrame(frame_number, std::move(output_buffer), capture_begin_time,
149 estimated_frame_duration, *storage, event_time, false);
150 return false;
151 }
152
153 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this,
154 frame_number, base::Passed(&output_buffer),
155 capture_begin_time, estimated_frame_duration);
156
157 return true;
158 }
159
160 bool ThreadSafeCaptureOracle::AttemptPassiveRefresh() {
161 const base::TimeTicks refresh_time = base::TimeTicks::Now();
162
163 scoped_refptr<VideoFrame> frame;
164 CaptureFrameCallback capture_callback;
165 if (!ObserveEventAndDecideCapture(VideoCaptureOracle::kPassiveRefreshRequest,
166 gfx::Rect(), refresh_time, &frame,
167 &capture_callback)) {
168 return false;
169 }
170
171 capture_callback.Run(frame, refresh_time, true);
172 return true;
173 }
174
175 gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const {
176 base::AutoLock guard(lock_);
177 return oracle_.capture_size();
178 }
179
180 void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
181 base::AutoLock guard(lock_);
182 VLOG(1) << "Source size changed to " << source_size.ToString();
183 oracle_.SetSourceSize(source_size);
184 }
185
186 void ThreadSafeCaptureOracle::Stop() {
187 base::AutoLock guard(lock_);
188 client_.reset();
189 }
190
191 void ThreadSafeCaptureOracle::ReportError(
192 const tracked_objects::Location& from_here,
193 const std::string& reason) {
194 base::AutoLock guard(lock_);
195 if (client_)
196 client_->OnError(from_here, reason);
197 }
198
199 void ThreadSafeCaptureOracle::DidCaptureFrame(
200 int frame_number,
201 std::unique_ptr<VideoCaptureDevice::Client::Buffer> buffer,
202 base::TimeTicks capture_begin_time,
203 base::TimeDelta estimated_frame_duration,
204 const scoped_refptr<VideoFrame>& frame,
205 base::TimeTicks reference_time,
206 bool success) {
207 TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(), "success",
208 success, "timestamp",
209 reference_time.ToInternalValue());
210
211 base::AutoLock guard(lock_);
212
213 if (oracle_.CompleteCapture(frame_number, success, &reference_time)) {
214 TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded",
215 TRACE_EVENT_SCOPE_THREAD);
216
217 if (!client_)
218 return; // Capture is stopped.
219
220 frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE,
221 params_.requested_format.frame_rate);
222 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME,
223 capture_begin_time);
224 frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME,
225 base::TimeTicks::Now());
226 frame->metadata()->SetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
227 estimated_frame_duration);
228 frame->metadata()->SetTimeTicks(VideoFrameMetadata::REFERENCE_TIME,
229 reference_time);
230
231 frame->AddDestructionObserver(
232 base::Bind(&ThreadSafeCaptureOracle::DidConsumeFrame, this,
233 frame_number, frame->metadata()));
234
235 client_->OnIncomingCapturedVideoFrame(std::move(buffer), frame);
236 }
237 }
238
239 void ThreadSafeCaptureOracle::DidConsumeFrame(
240 int frame_number,
241 const media::VideoFrameMetadata* metadata) {
242 // Note: This function may be called on any thread by the VideoFrame
243 // destructor. |metadata| is still valid for read-access at this point.
244 double utilization = -1.0;
245 if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION,
246 &utilization)) {
247 base::AutoLock guard(lock_);
248 oracle_.RecordConsumerFeedback(frame_number, utilization);
249 }
250 }
251
252 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/content/thread_safe_capture_oracle.h ('k') | media/capture/content/video_capture_oracle.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698