Chromium Code Reviews| 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, | |
|
Irfan
2016/04/06 19:53:05
I do not have the full picture here, but how does
miu
2016/04/06 22:33:53
From the oracle's point-of-view, the passive frame
| |
| 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 | |
| 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 |