| 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 |