OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/browser/renderer_host/media/desktop_capture_device.h" | 5 #include "content/browser/renderer_host/media/desktop_capture_device.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/sequenced_task_runner.h" | 10 #include "base/sequenced_task_runner.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 } // namespace | 46 } // namespace |
47 | 47 |
48 class DesktopCaptureDevice::Core | 48 class DesktopCaptureDevice::Core |
49 : public base::RefCountedThreadSafe<Core>, | 49 : public base::RefCountedThreadSafe<Core>, |
50 public webrtc::DesktopCapturer::Callback { | 50 public webrtc::DesktopCapturer::Callback { |
51 public: | 51 public: |
52 Core(scoped_refptr<base::SequencedTaskRunner> task_runner, | 52 Core(scoped_refptr<base::SequencedTaskRunner> task_runner, |
53 scoped_ptr<webrtc::DesktopCapturer> capturer); | 53 scoped_ptr<webrtc::DesktopCapturer> capturer); |
54 | 54 |
55 // Implementation of VideoCaptureDevice methods. | 55 // Implementation of VideoCaptureDevice methods. |
56 void AllocateAndStart(const media::VideoCaptureParams& params, | 56 void AllocateAndStart(const media::VideoCaptureCapability& capture_format, |
57 scoped_ptr<Client> client); | 57 scoped_ptr<Client> client); |
58 void StopAndDeAllocate(); | 58 void StopAndDeAllocate(); |
59 | 59 |
60 private: | 60 private: |
61 friend class base::RefCountedThreadSafe<Core>; | 61 friend class base::RefCountedThreadSafe<Core>; |
62 virtual ~Core(); | 62 virtual ~Core(); |
63 | 63 |
64 // webrtc::DesktopCapturer::Callback interface | 64 // webrtc::DesktopCapturer::Callback interface |
65 virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; | 65 virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; |
66 virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; | 66 virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; |
67 | 67 |
68 // Helper methods that run on the |task_runner_|. Posted from the | 68 // Helper methods that run on the |task_runner_|. Posted from the |
69 // corresponding public methods. | 69 // corresponding public methods. |
70 void DoAllocateAndStart(const media::VideoCaptureParams& params, | 70 void DoAllocateAndStart(const media::VideoCaptureCapability& capture_format, |
71 scoped_ptr<Client> client); | 71 scoped_ptr<Client> client); |
72 void DoStopAndDeAllocate(); | 72 void DoStopAndDeAllocate(); |
73 | 73 |
74 // Chooses new output properties based on the supplied source size and the | 74 // Chooses new output properties based on the supplied source size and the |
75 // properties requested to Allocate(), and dispatches OnFrameInfo[Changed] | 75 // properties requested to Allocate(), and dispatches OnFrameInfo[Changed] |
76 // notifications. | 76 // notifications. |
77 void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size); | 77 void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size); |
78 | 78 |
79 // Method that is scheduled on |task_runner_| to be called on regular interval | 79 // Method that is scheduled on |task_runner_| to be called on regular interval |
80 // to capture a frame. | 80 // to capture a frame. |
81 void OnCaptureTimer(); | 81 void OnCaptureTimer(); |
82 | 82 |
83 // Captures a frame and schedules timer for the next one. | 83 // Captures a frame and schedules timer for the next one. |
84 void CaptureFrameAndScheduleNext(); | 84 void CaptureFrameAndScheduleNext(); |
85 | 85 |
86 // Captures a single frame. | 86 // Captures a single frame. |
87 void DoCapture(); | 87 void DoCapture(); |
88 | 88 |
89 // Task runner used for capturing operations. | 89 // Task runner used for capturing operations. |
90 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 90 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
91 | 91 |
92 // The underlying DesktopCapturer instance used to capture frames. | 92 // The underlying DesktopCapturer instance used to capture frames. |
93 scoped_ptr<webrtc::DesktopCapturer> desktop_capturer_; | 93 scoped_ptr<webrtc::DesktopCapturer> desktop_capturer_; |
94 | 94 |
95 // The device client which proxies device events to the controller. Accessed | 95 // The device client which proxies device events to the controller. Accessed |
96 // on the task_runner_ thread. | 96 // on the task_runner_ thread. |
97 scoped_ptr<Client> client_; | 97 scoped_ptr<Client> client_; |
98 | 98 |
99 // Requested video capture format (width, height, frame rate, etc). | 99 // Requested video capture format (width, height, frame rate, etc). |
100 media::VideoCaptureParams requested_params_; | 100 media::VideoCaptureCapability requested_format_; |
101 | 101 |
102 // Actual video capture format being generated. | 102 // Actual video capture format being generated. |
103 media::VideoCaptureFormat capture_format_; | 103 media::VideoCaptureCapability capture_format_; |
104 | 104 |
105 // Size of frame most recently captured from the source. | 105 // Size of frame most recently captured from the source. |
106 webrtc::DesktopSize previous_frame_size_; | 106 webrtc::DesktopSize previous_frame_size_; |
107 | 107 |
108 // DesktopFrame into which captured frames are down-scaled and/or letterboxed, | 108 // DesktopFrame into which captured frames are down-scaled and/or letterboxed, |
109 // depending upon the caller's requested capture capabilities. If frames can | 109 // depending upon the caller's requested capture capabilities. If frames can |
110 // be returned to the caller directly then this is NULL. | 110 // be returned to the caller directly then this is NULL. |
111 scoped_ptr<webrtc::DesktopFrame> output_frame_; | 111 scoped_ptr<webrtc::DesktopFrame> output_frame_; |
112 | 112 |
113 // Sub-rectangle of |output_frame_| into which the source will be scaled | 113 // Sub-rectangle of |output_frame_| into which the source will be scaled |
(...skipping 15 matching lines...) Expand all Loading... |
129 scoped_ptr<webrtc::DesktopCapturer> capturer) | 129 scoped_ptr<webrtc::DesktopCapturer> capturer) |
130 : task_runner_(task_runner), | 130 : task_runner_(task_runner), |
131 desktop_capturer_(capturer.Pass()), | 131 desktop_capturer_(capturer.Pass()), |
132 capture_task_posted_(false), | 132 capture_task_posted_(false), |
133 capture_in_progress_(false) {} | 133 capture_in_progress_(false) {} |
134 | 134 |
135 DesktopCaptureDevice::Core::~Core() { | 135 DesktopCaptureDevice::Core::~Core() { |
136 } | 136 } |
137 | 137 |
138 void DesktopCaptureDevice::Core::AllocateAndStart( | 138 void DesktopCaptureDevice::Core::AllocateAndStart( |
139 const media::VideoCaptureParams& params, | 139 const media::VideoCaptureCapability& capture_format, |
140 scoped_ptr<Client> client) { | 140 scoped_ptr<Client> client) { |
141 DCHECK_GT(params.requested_format.frame_size.GetArea(), 0); | 141 DCHECK_GT(capture_format.width, 0); |
142 DCHECK_GT(params.requested_format.frame_rate, 0); | 142 DCHECK_GT(capture_format.height, 0); |
| 143 DCHECK_GT(capture_format.frame_rate, 0); |
143 | 144 |
144 task_runner_->PostTask( | 145 task_runner_->PostTask( |
145 FROM_HERE, | 146 FROM_HERE, |
146 base::Bind( | 147 base::Bind(&Core::DoAllocateAndStart, |
147 &Core::DoAllocateAndStart, this, params, base::Passed(&client))); | 148 this, |
| 149 capture_format, |
| 150 base::Passed(&client))); |
148 } | 151 } |
149 | 152 |
150 void DesktopCaptureDevice::Core::StopAndDeAllocate() { | 153 void DesktopCaptureDevice::Core::StopAndDeAllocate() { |
151 task_runner_->PostTask(FROM_HERE, | 154 task_runner_->PostTask(FROM_HERE, |
152 base::Bind(&Core::DoStopAndDeAllocate, this)); | 155 base::Bind(&Core::DoStopAndDeAllocate, this)); |
153 } | 156 } |
154 | 157 |
155 webrtc::SharedMemory* | 158 webrtc::SharedMemory* |
156 DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) { | 159 DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) { |
157 return NULL; | 160 return NULL; |
(...skipping 13 matching lines...) Expand all Loading... |
171 } | 174 } |
172 | 175 |
173 if (!client_) | 176 if (!client_) |
174 return; | 177 return; |
175 | 178 |
176 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); | 179 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); |
177 | 180 |
178 // Handle initial frame size and size changes. | 181 // Handle initial frame size and size changes. |
179 RefreshCaptureFormat(frame->size()); | 182 RefreshCaptureFormat(frame->size()); |
180 | 183 |
181 webrtc::DesktopSize output_size(capture_format_.frame_size.width(), | 184 webrtc::DesktopSize output_size(capture_format_.width, |
182 capture_format_.frame_size.height()); | 185 capture_format_.height); |
183 size_t output_bytes = output_size.width() * output_size.height() * | 186 size_t output_bytes = output_size.width() * output_size.height() * |
184 webrtc::DesktopFrame::kBytesPerPixel; | 187 webrtc::DesktopFrame::kBytesPerPixel; |
185 const uint8_t* output_data = NULL; | 188 const uint8_t* output_data = NULL; |
186 | 189 |
187 if (frame->size().equals(output_size)) { | 190 if (frame->size().equals(output_size)) { |
188 // If the captured frame matches the output size, we can return the pixel | 191 // If the captured frame matches the output size, we can return the pixel |
189 // data directly, without scaling. | 192 // data directly, without scaling. |
190 output_data = frame->data(); | 193 output_data = frame->data(); |
191 } else { | 194 } else { |
192 // Otherwise we need to down-scale and/or letterbox to the target format. | 195 // Otherwise we need to down-scale and/or letterbox to the target format. |
(...skipping 25 matching lines...) Expand all Loading... |
218 output_bytes, | 221 output_bytes, |
219 base::Time::Now(), | 222 base::Time::Now(), |
220 0, | 223 0, |
221 false, | 224 false, |
222 false, | 225 false, |
223 capture_format_); | 226 capture_format_); |
224 } | 227 } |
225 } | 228 } |
226 | 229 |
227 void DesktopCaptureDevice::Core::DoAllocateAndStart( | 230 void DesktopCaptureDevice::Core::DoAllocateAndStart( |
228 const media::VideoCaptureParams& params, | 231 const media::VideoCaptureCapability& capture_format, |
229 scoped_ptr<Client> client) { | 232 scoped_ptr<Client> client) { |
230 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 233 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
231 DCHECK(desktop_capturer_); | 234 DCHECK(desktop_capturer_); |
232 DCHECK(client.get()); | 235 DCHECK(client.get()); |
233 DCHECK(!client_.get()); | 236 DCHECK(!client_.get()); |
234 | 237 |
235 client_ = client.Pass(); | 238 client_ = client.Pass(); |
236 requested_params_ = params; | 239 requested_format_ = capture_format; |
237 | 240 |
238 capture_format_ = requested_params_.requested_format; | 241 capture_format_.frame_rate = requested_format_.frame_rate; |
| 242 |
| 243 // Support dynamic changes in resolution only if requester also does. |
| 244 if (requested_format_.frame_size_type == |
| 245 media::VariableResolutionVideoCaptureDevice) { |
| 246 capture_format_.frame_size_type = |
| 247 media::VariableResolutionVideoCaptureDevice; |
| 248 } |
239 | 249 |
240 // This capturer always outputs ARGB, non-interlaced. | 250 // This capturer always outputs ARGB, non-interlaced. |
241 capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB; | 251 capture_format_.color = media::PIXEL_FORMAT_ARGB; |
242 | 252 |
243 desktop_capturer_->Start(this); | 253 desktop_capturer_->Start(this); |
244 | 254 |
245 CaptureFrameAndScheduleNext(); | 255 CaptureFrameAndScheduleNext(); |
246 } | 256 } |
247 | 257 |
248 void DesktopCaptureDevice::Core::DoStopAndDeAllocate() { | 258 void DesktopCaptureDevice::Core::DoStopAndDeAllocate() { |
249 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 259 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
250 client_.reset(); | 260 client_.reset(); |
251 output_frame_.reset(); | 261 output_frame_.reset(); |
252 previous_frame_size_.set(0, 0); | 262 previous_frame_size_.set(0, 0); |
253 desktop_capturer_.reset(); | 263 desktop_capturer_.reset(); |
254 } | 264 } |
255 | 265 |
256 void DesktopCaptureDevice::Core::RefreshCaptureFormat( | 266 void DesktopCaptureDevice::Core::RefreshCaptureFormat( |
257 const webrtc::DesktopSize& frame_size) { | 267 const webrtc::DesktopSize& frame_size) { |
258 if (previous_frame_size_.equals(frame_size)) | 268 if (previous_frame_size_.equals(frame_size)) |
259 return; | 269 return; |
260 | 270 |
261 // Clear the output frame, if any, since it will either need resizing, or | 271 // Clear the output frame, if any, since it will either need resizing, or |
262 // clearing of stale data in letterbox areas, anyway. | 272 // clearing of stale data in letterbox areas, anyway. |
263 output_frame_.reset(); | 273 output_frame_.reset(); |
264 | 274 |
265 if (previous_frame_size_.is_empty() || | 275 if (previous_frame_size_.is_empty() || |
266 requested_params_.allow_resolution_change) { | 276 requested_format_.frame_size_type == |
| 277 media::VariableResolutionVideoCaptureDevice) { |
267 // If this is the first frame, or the receiver supports variable resolution | 278 // If this is the first frame, or the receiver supports variable resolution |
268 // then determine the output size by treating the requested width & height | 279 // then determine the output size by treating the requested width & height |
269 // as maxima. | 280 // as maxima. |
270 if (frame_size.width() > | 281 if (frame_size.width() > requested_format_.width || |
271 requested_params_.requested_format.frame_size.width() || | 282 frame_size.height() > requested_format_.height) { |
272 frame_size.height() > | |
273 requested_params_.requested_format.frame_size.height()) { | |
274 output_rect_ = ComputeLetterboxRect( | 283 output_rect_ = ComputeLetterboxRect( |
275 webrtc::DesktopSize( | 284 webrtc::DesktopSize(requested_format_.width, |
276 requested_params_.requested_format.frame_size.width(), | 285 requested_format_.height), |
277 requested_params_.requested_format.frame_size.height()), | |
278 frame_size); | 286 frame_size); |
279 output_rect_.Translate(-output_rect_.left(), -output_rect_.top()); | 287 output_rect_.Translate(-output_rect_.left(), -output_rect_.top()); |
280 } else { | 288 } else { |
281 output_rect_ = webrtc::DesktopRect::MakeSize(frame_size); | 289 output_rect_ = webrtc::DesktopRect::MakeSize(frame_size); |
282 } | 290 } |
283 capture_format_.frame_size.SetSize(output_rect_.width(), | 291 capture_format_.width = output_rect_.width(); |
284 output_rect_.height()); | 292 capture_format_.height = output_rect_.height(); |
285 } else { | 293 } else { |
286 // Otherwise the output frame size cannot change, so just scale and | 294 // Otherwise the output frame size cannot change, so just scale and |
287 // letterbox. | 295 // letterbox. |
288 output_rect_ = ComputeLetterboxRect( | 296 output_rect_ = ComputeLetterboxRect( |
289 webrtc::DesktopSize(capture_format_.frame_size.width(), | 297 webrtc::DesktopSize(capture_format_.width, capture_format_.height), |
290 capture_format_.frame_size.height()), | |
291 frame_size); | 298 frame_size); |
292 } | 299 } |
293 | 300 |
294 previous_frame_size_ = frame_size; | 301 previous_frame_size_ = frame_size; |
295 } | 302 } |
296 | 303 |
297 void DesktopCaptureDevice::Core::OnCaptureTimer() { | 304 void DesktopCaptureDevice::Core::OnCaptureTimer() { |
298 DCHECK(capture_task_posted_); | 305 DCHECK(capture_task_posted_); |
299 capture_task_posted_ = false; | 306 capture_task_posted_ = false; |
300 | 307 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 DesktopCaptureDevice::DesktopCaptureDevice( | 404 DesktopCaptureDevice::DesktopCaptureDevice( |
398 scoped_refptr<base::SequencedTaskRunner> task_runner, | 405 scoped_refptr<base::SequencedTaskRunner> task_runner, |
399 scoped_ptr<webrtc::DesktopCapturer> capturer) | 406 scoped_ptr<webrtc::DesktopCapturer> capturer) |
400 : core_(new Core(task_runner, capturer.Pass())) {} | 407 : core_(new Core(task_runner, capturer.Pass())) {} |
401 | 408 |
402 DesktopCaptureDevice::~DesktopCaptureDevice() { | 409 DesktopCaptureDevice::~DesktopCaptureDevice() { |
403 StopAndDeAllocate(); | 410 StopAndDeAllocate(); |
404 } | 411 } |
405 | 412 |
406 void DesktopCaptureDevice::AllocateAndStart( | 413 void DesktopCaptureDevice::AllocateAndStart( |
407 const media::VideoCaptureParams& params, | 414 const media::VideoCaptureCapability& capture_format, |
408 scoped_ptr<Client> client) { | 415 scoped_ptr<Client> client) { |
409 core_->AllocateAndStart(params, client.Pass()); | 416 core_->AllocateAndStart(capture_format, client.Pass()); |
410 } | 417 } |
411 | 418 |
412 void DesktopCaptureDevice::StopAndDeAllocate() { | 419 void DesktopCaptureDevice::StopAndDeAllocate() { |
413 core_->StopAndDeAllocate(); | 420 core_->StopAndDeAllocate(); |
414 } | 421 } |
415 | 422 |
416 } // namespace content | 423 } // namespace content |
OLD | NEW |