OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 ~ControllerClient() {} | 42 ~ControllerClient() {} |
43 | 43 |
44 // ID used for identifying this object. | 44 // ID used for identifying this object. |
45 VideoCaptureControllerID controller_id; | 45 VideoCaptureControllerID controller_id; |
46 VideoCaptureControllerEventHandler* event_handler; | 46 VideoCaptureControllerEventHandler* event_handler; |
47 | 47 |
48 // Handle to the render process that will receive the capture buffers. | 48 // Handle to the render process that will receive the capture buffers. |
49 base::ProcessHandle render_process_handle; | 49 base::ProcessHandle render_process_handle; |
50 media::VideoCaptureParams parameters; | 50 media::VideoCaptureParams parameters; |
51 | 51 |
52 // Buffers used by this client. | 52 // Buffers that are currently known to this client. |
53 std::set<int> buffers; | 53 std::set<int> known_buffers; |
| 54 |
| 55 // Buffers currently held by this client. |
| 56 std::set<int> active_buffers; |
54 | 57 |
55 // State of capture session, controlled by VideoCaptureManager directly. This | 58 // State of capture session, controlled by VideoCaptureManager directly. This |
56 // transitions to true as soon as StopSession() occurs, at which point the | 59 // transitions to true as soon as StopSession() occurs, at which point the |
57 // client is sent an OnEnded() event. However, because the client retains a | 60 // client is sent an OnEnded() event. However, because the client retains a |
58 // VideoCaptureController* pointer, its ControllerClient entry lives on until | 61 // VideoCaptureController* pointer, its ControllerClient entry lives on until |
59 // it unregisters itself via RemoveClient(), which may happen asynchronously. | 62 // it unregisters itself via RemoveClient(), which may happen asynchronously. |
60 // | 63 // |
61 // TODO(nick): If we changed the semantics of VideoCaptureHost so that | 64 // TODO(nick): If we changed the semantics of VideoCaptureHost so that |
62 // OnEnded() events were processed synchronously (with the RemoveClient() done | 65 // OnEnded() events were processed synchronously (with the RemoveClient() done |
63 // implicitly), we could avoid tracking this state here in the Controller, and | 66 // implicitly), we could avoid tracking this state here in the Controller, and |
64 // simplify the code in both places. | 67 // simplify the code in both places. |
65 bool session_closed; | 68 bool session_closed; |
66 }; | 69 }; |
67 | 70 |
68 // Receives events from the VideoCaptureDevice and posts them to a | 71 // Receives events from the VideoCaptureDevice and posts them to a |
69 // VideoCaptureController on the IO thread. An instance of this class may safely | 72 // VideoCaptureController on the IO thread. An instance of this class may safely |
70 // outlive its target VideoCaptureController. | 73 // outlive its target VideoCaptureController. |
71 // | 74 // |
72 // Methods of this class may be called from any thread, and in practice will | 75 // Methods of this class may be called from any thread, and in practice will |
73 // often be called on some auxiliary thread depending on the platform and the | 76 // often be called on some auxiliary thread depending on the platform and the |
74 // device type; including, for example, the DirectShow thread on Windows, the | 77 // device type; including, for example, the DirectShow thread on Windows, the |
75 // v4l2_thread on Linux, and the UI thread for tab capture. | 78 // v4l2_thread on Linux, and the UI thread for tab capture. |
76 class VideoCaptureController::VideoCaptureDeviceClient | 79 class VideoCaptureController::VideoCaptureDeviceClient |
77 : public media::VideoCaptureDevice::Client { | 80 : public media::VideoCaptureDevice::Client { |
78 public: | 81 public: |
79 explicit VideoCaptureDeviceClient( | 82 explicit VideoCaptureDeviceClient( |
80 const base::WeakPtr<VideoCaptureController>& controller); | 83 const base::WeakPtr<VideoCaptureController>& controller, |
| 84 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); |
81 virtual ~VideoCaptureDeviceClient(); | 85 virtual ~VideoCaptureDeviceClient(); |
82 | 86 |
83 // VideoCaptureDevice::Client implementation. | 87 // VideoCaptureDevice::Client implementation. |
84 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() OVERRIDE; | 88 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer( |
| 89 const gfx::Size& size) OVERRIDE; |
85 virtual void OnIncomingCapturedFrame(const uint8* data, | 90 virtual void OnIncomingCapturedFrame(const uint8* data, |
86 int length, | 91 int length, |
87 base::Time timestamp, | 92 base::Time timestamp, |
88 int rotation, | 93 int rotation, |
89 bool flip_vert, | 94 bool flip_vert, |
90 bool flip_horiz) OVERRIDE; | 95 bool flip_horiz) OVERRIDE; |
91 virtual void OnIncomingCapturedVideoFrame( | 96 virtual void OnIncomingCapturedVideoFrame( |
92 const scoped_refptr<media::VideoFrame>& frame, | 97 const scoped_refptr<media::VideoFrame>& frame, |
93 base::Time timestamp) OVERRIDE; | 98 base::Time timestamp) OVERRIDE; |
94 virtual void OnError() OVERRIDE; | 99 virtual void OnError() OVERRIDE; |
95 virtual void OnFrameInfo( | 100 virtual void OnFrameInfo( |
96 const media::VideoCaptureCapability& info) OVERRIDE; | 101 const media::VideoCaptureCapability& info) OVERRIDE; |
97 virtual void OnFrameInfoChanged( | 102 virtual void OnFrameInfoChanged( |
98 const media::VideoCaptureCapability& info) OVERRIDE; | 103 const media::VideoCaptureCapability& info) OVERRIDE; |
99 | 104 |
100 private: | 105 private: |
| 106 scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame( |
| 107 const gfx::Size& size, |
| 108 int rotation); |
| 109 |
101 // The controller to which we post events. | 110 // The controller to which we post events. |
102 const base::WeakPtr<VideoCaptureController> controller_; | 111 const base::WeakPtr<VideoCaptureController> controller_; |
103 | 112 |
104 // The pool of shared-memory buffers used for capturing. | 113 // The pool of shared-memory buffers used for capturing. |
105 scoped_refptr<VideoCaptureBufferPool> buffer_pool_; | 114 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; |
106 | 115 |
107 // Chopped pixels in width/height in case video capture device has odd | 116 // Chopped pixels in width/height in case video capture device has odd |
108 // numbers for width/height. | 117 // numbers for width/height. |
109 int chopped_width_; | 118 int chopped_width_; |
110 int chopped_height_; | 119 int chopped_height_; |
111 | 120 |
112 // Tracks the current frame format. | 121 // Tracks the current frame format. |
113 media::VideoCaptureCapability frame_info_; | 122 media::VideoCaptureCapability frame_info_; |
114 }; | 123 }; |
115 | 124 |
116 VideoCaptureController::VideoCaptureController() | 125 VideoCaptureController::VideoCaptureController() |
117 : state_(VIDEO_CAPTURE_STATE_STARTED), | 126 : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)), |
| 127 state_(VIDEO_CAPTURE_STATE_STARTED), |
118 weak_ptr_factory_(this) { | 128 weak_ptr_factory_(this) { |
119 memset(¤t_params_, 0, sizeof(current_params_)); | |
120 } | 129 } |
121 | 130 |
122 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 131 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
123 const base::WeakPtr<VideoCaptureController>& controller) | 132 const base::WeakPtr<VideoCaptureController>& controller, |
| 133 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) |
124 : controller_(controller), | 134 : controller_(controller), |
| 135 buffer_pool_(buffer_pool), |
125 chopped_width_(0), | 136 chopped_width_(0), |
126 chopped_height_(0) {} | 137 chopped_height_(0) {} |
127 | 138 |
128 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} | 139 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} |
129 | 140 |
130 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { | 141 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { |
131 return weak_ptr_factory_.GetWeakPtr(); | 142 return weak_ptr_factory_.GetWeakPtr(); |
132 } | 143 } |
133 | 144 |
134 scoped_ptr<media::VideoCaptureDevice::Client> | 145 scoped_ptr<media::VideoCaptureDevice::Client> |
135 VideoCaptureController::NewDeviceClient() { | 146 VideoCaptureController::NewDeviceClient() { |
136 scoped_ptr<media::VideoCaptureDevice::Client> result( | 147 scoped_ptr<media::VideoCaptureDevice::Client> result( |
137 new VideoCaptureDeviceClient(this->GetWeakPtr())); | 148 new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_)); |
138 return result.Pass(); | 149 return result.Pass(); |
139 } | 150 } |
140 | 151 |
141 void VideoCaptureController::AddClient( | 152 void VideoCaptureController::AddClient( |
142 const VideoCaptureControllerID& id, | 153 const VideoCaptureControllerID& id, |
143 VideoCaptureControllerEventHandler* event_handler, | 154 VideoCaptureControllerEventHandler* event_handler, |
144 base::ProcessHandle render_process, | 155 base::ProcessHandle render_process, |
145 const media::VideoCaptureParams& params) { | 156 const media::VideoCaptureParams& params) { |
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
147 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id | 158 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id |
148 << ", (" << params.width | 159 << ", (" << params.requested_format.width |
149 << ", " << params.height | 160 << ", " << params.requested_format.height |
150 << ", " << params.frame_rate | 161 << ", " << params.requested_format.frame_rate |
151 << ", " << params.session_id | 162 << ", " << params.session_id |
152 << ")"; | 163 << ")"; |
153 | 164 |
154 // Signal error in case device is already in error state. | 165 // Signal error in case device is already in error state. |
155 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { | 166 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { |
156 event_handler->OnError(id); | 167 event_handler->OnError(id); |
157 return; | 168 return; |
158 } | 169 } |
159 | 170 |
160 // Do nothing if this client has called AddClient before. | 171 // Do nothing if this client has called AddClient before. |
161 if (FindClient(id, event_handler, controller_clients_)) | 172 if (FindClient(id, event_handler, controller_clients_)) |
162 return; | 173 return; |
163 | 174 |
164 ControllerClient* client = new ControllerClient(id, event_handler, | 175 ControllerClient* client = new ControllerClient(id, event_handler, |
165 render_process, params); | 176 render_process, params); |
166 // If we already have gotten frame_info from the device, repeat it to the new | 177 // If we already have gotten frame_info from the device, repeat it to the new |
167 // client. | 178 // client. |
168 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 179 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
169 if (frame_info_.IsValid()) { | |
170 SendFrameInfoAndBuffers(client); | |
171 } | |
172 controller_clients_.push_back(client); | 180 controller_clients_.push_back(client); |
173 return; | 181 return; |
174 } | 182 } |
175 } | 183 } |
176 | 184 |
177 int VideoCaptureController::RemoveClient( | 185 int VideoCaptureController::RemoveClient( |
178 const VideoCaptureControllerID& id, | 186 const VideoCaptureControllerID& id, |
179 VideoCaptureControllerEventHandler* event_handler) { | 187 VideoCaptureControllerEventHandler* event_handler) { |
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
181 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id; | 189 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id; |
182 | 190 |
183 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 191 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
184 if (!client) | 192 if (!client) |
185 return kInvalidMediaCaptureSessionId; | 193 return kInvalidMediaCaptureSessionId; |
186 | 194 |
187 // Take back all buffers held by the |client|. | 195 // Take back all buffers held by the |client|. |
188 if (buffer_pool_.get()) { | 196 for (std::set<int>::iterator buffer_it = client->active_buffers.begin(); |
189 for (std::set<int>::iterator buffer_it = client->buffers.begin(); | 197 buffer_it != client->active_buffers.end(); |
190 buffer_it != client->buffers.end(); | 198 ++buffer_it) { |
191 ++buffer_it) { | 199 int buffer_id = *buffer_it; |
192 int buffer_id = *buffer_it; | 200 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
193 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | |
194 } | |
195 } | 201 } |
196 client->buffers.clear(); | 202 client->active_buffers.clear(); |
197 | 203 |
198 int session_id = client->parameters.session_id; | 204 int session_id = client->parameters.session_id; |
199 controller_clients_.remove(client); | 205 controller_clients_.remove(client); |
200 delete client; | 206 delete client; |
201 | 207 |
202 return session_id; | 208 return session_id; |
203 } | 209 } |
204 | 210 |
205 void VideoCaptureController::StopSession(int session_id) { | 211 void VideoCaptureController::StopSession(int session_id) { |
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
(...skipping 10 matching lines...) Expand all Loading... |
217 void VideoCaptureController::ReturnBuffer( | 223 void VideoCaptureController::ReturnBuffer( |
218 const VideoCaptureControllerID& id, | 224 const VideoCaptureControllerID& id, |
219 VideoCaptureControllerEventHandler* event_handler, | 225 VideoCaptureControllerEventHandler* event_handler, |
220 int buffer_id) { | 226 int buffer_id) { |
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
222 | 228 |
223 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 229 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
224 | 230 |
225 // If this buffer is not held by this client, or this client doesn't exist | 231 // If this buffer is not held by this client, or this client doesn't exist |
226 // in controller, do nothing. | 232 // in controller, do nothing. |
227 if (!client || | 233 if (!client || !client->active_buffers.erase(buffer_id)) { |
228 client->buffers.find(buffer_id) == client->buffers.end()) { | |
229 NOTREACHED(); | 234 NOTREACHED(); |
230 return; | 235 return; |
231 } | 236 } |
232 | 237 |
233 client->buffers.erase(buffer_id); | |
234 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 238 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
235 } | 239 } |
236 | 240 |
237 scoped_refptr<media::VideoFrame> | 241 scoped_refptr<media::VideoFrame> |
238 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() { | 242 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( |
239 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | 243 const gfx::Size& size) { |
240 frame_info_.height), | 244 return DoReserveI420VideoFrame(size, 0); |
241 0); | |
242 } | 245 } |
243 | 246 |
244 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | 247 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( |
245 const uint8* data, | 248 const uint8* data, |
246 int length, | 249 int length, |
247 base::Time timestamp, | 250 base::Time timestamp, |
248 int rotation, | 251 int rotation, |
249 bool flip_vert, | 252 bool flip_vert, |
250 bool flip_horiz) { | 253 bool flip_horiz) { |
251 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 254 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
252 | 255 |
253 if (!buffer_pool_.get()) | 256 if (!frame_info_.IsValid()) |
254 return; | 257 return; |
255 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame( | 258 |
| 259 scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame( |
256 gfx::Size(frame_info_.width, frame_info_.height), rotation); | 260 gfx::Size(frame_info_.width, frame_info_.height), rotation); |
257 | 261 |
258 if (!dst.get()) | 262 if (!dst.get()) |
259 return; | 263 return; |
260 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 264 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
261 | 265 |
262 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 266 uint8* yplane = dst->data(media::VideoFrame::kYPlane); |
263 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 267 uint8* uplane = dst->data(media::VideoFrame::kUPlane); |
264 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 268 uint8* vplane = dst->data(media::VideoFrame::kVPlane); |
265 int yplane_stride = frame_info_.width; | 269 int yplane_stride = frame_info_.width; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 // not used in those builds either. Whenever libyuv is added in that build, | 384 // not used in those builds either. Whenever libyuv is added in that build, |
381 // address all these #ifdef parts, see http://crbug.com/299611 . | 385 // address all these #ifdef parts, see http://crbug.com/299611 . |
382 NOTREACHED(); | 386 NOTREACHED(); |
383 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 387 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
384 BrowserThread::PostTask( | 388 BrowserThread::PostTask( |
385 BrowserThread::IO, | 389 BrowserThread::IO, |
386 FROM_HERE, | 390 FROM_HERE, |
387 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 391 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
388 controller_, | 392 controller_, |
389 dst, | 393 dst, |
| 394 frame_info_.frame_rate, |
390 timestamp)); | 395 timestamp)); |
391 } | 396 } |
392 | 397 |
393 void | 398 void |
394 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 399 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( |
395 const scoped_refptr<media::VideoFrame>& frame, | 400 const scoped_refptr<media::VideoFrame>& frame, |
396 base::Time timestamp) { | 401 base::Time timestamp) { |
397 if (!buffer_pool_) | |
398 return; | |
399 | 402 |
400 // If this is a frame that belongs to the buffer pool, we can forward it | 403 // If this is a frame that belongs to the buffer pool, we can forward it |
401 // directly to the IO thread and be done. | 404 // directly to the IO thread and be done. |
402 if (buffer_pool_->RecognizeReservedBuffer( | 405 if (buffer_pool_->RecognizeReservedBuffer( |
403 frame->shared_memory_handle()) >= 0) { | 406 frame->shared_memory_handle()) >= 0) { |
404 BrowserThread::PostTask(BrowserThread::IO, | 407 BrowserThread::PostTask(BrowserThread::IO, |
405 FROM_HERE, | 408 FROM_HERE, |
406 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 409 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
407 controller_, frame, timestamp)); | 410 controller_, frame, frame_info_.frame_rate, timestamp)); |
408 return; | 411 return; |
409 } | 412 } |
410 | 413 |
411 // Otherwise, this is a frame that belongs to the caller, and we must copy | 414 NOTREACHED() << "Frames should always belong to the buffer pool."; |
412 // it to a frame from the buffer pool. | |
413 scoped_refptr<media::VideoFrame> target = | |
414 buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | |
415 frame_info_.height), | |
416 0); | |
417 | |
418 if (!target.get()) | |
419 return; | |
420 | |
421 // Validate the inputs. | |
422 if (frame->coded_size() != target->coded_size()) | |
423 return; // Only exact copies are supported. | |
424 if (!(frame->format() == media::VideoFrame::I420 || | |
425 frame->format() == media::VideoFrame::YV12 || | |
426 frame->format() == media::VideoFrame::RGB32)) { | |
427 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; | |
428 return; | |
429 } | |
430 | |
431 const int kYPlane = media::VideoFrame::kYPlane; | |
432 const int kUPlane = media::VideoFrame::kUPlane; | |
433 const int kVPlane = media::VideoFrame::kVPlane; | |
434 const int kAPlane = media::VideoFrame::kAPlane; | |
435 const int kRGBPlane = media::VideoFrame::kRGBPlane; | |
436 | |
437 // Do color conversion from the camera format to I420. | |
438 switch (frame->format()) { | |
439 #if defined(GOOGLE_TV) | |
440 case media::VideoFrame::HOLE: | |
441 // Fall-through to NOTREACHED() block. | |
442 #endif | |
443 case media::VideoFrame::INVALID: | |
444 case media::VideoFrame::YV16: | |
445 case media::VideoFrame::EMPTY: | |
446 case media::VideoFrame::NATIVE_TEXTURE: { | |
447 NOTREACHED(); | |
448 break; | |
449 } | |
450 case media::VideoFrame::I420: | |
451 case media::VideoFrame::YV12: { | |
452 DCHECK(!chopped_width_ && !chopped_height_); | |
453 media::CopyYPlane(frame->data(kYPlane), | |
454 frame->stride(kYPlane), | |
455 frame->rows(kYPlane), | |
456 target.get()); | |
457 media::CopyUPlane(frame->data(kUPlane), | |
458 frame->stride(kUPlane), | |
459 frame->rows(kUPlane), | |
460 target.get()); | |
461 media::CopyVPlane(frame->data(kVPlane), | |
462 frame->stride(kVPlane), | |
463 frame->rows(kVPlane), | |
464 target.get()); | |
465 break; | |
466 } | |
467 case media::VideoFrame::YV12A: { | |
468 DCHECK(!chopped_width_ && !chopped_height_); | |
469 media::CopyYPlane(frame->data(kYPlane), | |
470 frame->stride(kYPlane), | |
471 frame->rows(kYPlane), | |
472 target.get()); | |
473 media::CopyUPlane(frame->data(kUPlane), | |
474 frame->stride(kUPlane), | |
475 frame->rows(kUPlane), | |
476 target.get()); | |
477 media::CopyVPlane(frame->data(kVPlane), | |
478 frame->stride(kVPlane), | |
479 frame->rows(kVPlane), | |
480 target.get()); | |
481 media::CopyAPlane(frame->data(kAPlane), | |
482 frame->stride(kAPlane), | |
483 frame->rows(kAPlane), | |
484 target.get()); | |
485 break; | |
486 } | |
487 case media::VideoFrame::RGB32: { | |
488 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), | |
489 target->data(kYPlane), | |
490 target->data(kUPlane), | |
491 target->data(kVPlane), | |
492 target->coded_size().width(), | |
493 target->coded_size().height(), | |
494 frame->stride(kRGBPlane), | |
495 target->stride(kYPlane), | |
496 target->stride(kUPlane)); | |
497 break; | |
498 } | |
499 } | |
500 | |
501 BrowserThread::PostTask(BrowserThread::IO, | |
502 FROM_HERE, | |
503 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
504 controller_, target, timestamp)); | |
505 } | 415 } |
506 | 416 |
507 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { | 417 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { |
508 BrowserThread::PostTask(BrowserThread::IO, | 418 BrowserThread::PostTask(BrowserThread::IO, |
509 FROM_HERE, | 419 FROM_HERE, |
510 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); | 420 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); |
511 } | 421 } |
512 | 422 |
513 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( | 423 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( |
514 const media::VideoCaptureCapability& info) { | 424 const media::VideoCaptureCapability& info) { |
515 frame_info_ = info; | 425 frame_info_ = info; |
516 // Handle cases when |info| has odd numbers for width/height. | 426 // Handle cases when |info| has odd numbers for width/height. |
517 if (info.width & 1) { | 427 if (info.width & 1) { |
518 --frame_info_.width; | 428 --frame_info_.width; |
519 chopped_width_ = 1; | 429 chopped_width_ = 1; |
520 } else { | 430 } else { |
521 chopped_width_ = 0; | 431 chopped_width_ = 0; |
522 } | 432 } |
523 if (info.height & 1) { | 433 if (info.height & 1) { |
524 --frame_info_.height; | 434 --frame_info_.height; |
525 chopped_height_ = 1; | 435 chopped_height_ = 1; |
526 } else { | 436 } else { |
527 chopped_height_ = 0; | 437 chopped_height_ = 0; |
528 } | 438 } |
529 | |
530 DCHECK(!buffer_pool_.get()); | |
531 | |
532 // TODO(nick): Give BufferPool the same lifetime as the controller, have it | |
533 // support frame size changes, and stop checking it for NULL everywhere. | |
534 // http://crbug.com/266082 | |
535 buffer_pool_ = new VideoCaptureBufferPool( | |
536 media::VideoFrame::AllocationSize( | |
537 media::VideoFrame::I420, | |
538 gfx::Size(frame_info_.width, frame_info_.height)), | |
539 kNoOfBuffers); | |
540 | |
541 // Check whether all buffers were created successfully. | |
542 if (!buffer_pool_->Allocate()) { | |
543 // Transition to the error state. | |
544 buffer_pool_ = NULL; | |
545 OnError(); | |
546 return; | |
547 } | |
548 | |
549 BrowserThread::PostTask(BrowserThread::IO, | |
550 FROM_HERE, | |
551 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, controller_, | |
552 frame_info_, buffer_pool_)); | |
553 } | 439 } |
554 | 440 |
555 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( | 441 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( |
556 const media::VideoCaptureCapability& info) { | 442 const media::VideoCaptureCapability& info) { |
557 BrowserThread::PostTask(BrowserThread::IO, | 443 OnFrameInfo(info); |
558 FROM_HERE, | 444 } |
559 base::Bind(&VideoCaptureController::DoFrameInfoChangedOnIOThread, | 445 |
560 controller_, info)); | 446 scoped_refptr<media::VideoFrame> |
| 447 VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame( |
| 448 const gfx::Size& size, |
| 449 int rotation) { |
| 450 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; |
| 451 scoped_refptr<media::VideoFrame> frame = |
| 452 buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop); |
| 453 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { |
| 454 BrowserThread::PostTask(BrowserThread::IO, |
| 455 FROM_HERE, |
| 456 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, |
| 457 controller_, buffer_id_to_drop)); |
| 458 } |
| 459 return frame; |
561 } | 460 } |
562 | 461 |
563 VideoCaptureController::~VideoCaptureController() { | 462 VideoCaptureController::~VideoCaptureController() { |
564 buffer_pool_ = NULL; // Release all buffers. | |
565 STLDeleteContainerPointers(controller_clients_.begin(), | 463 STLDeleteContainerPointers(controller_clients_.begin(), |
566 controller_clients_.end()); | 464 controller_clients_.end()); |
567 } | 465 } |
568 | 466 |
569 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 467 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
570 const scoped_refptr<media::VideoFrame>& reserved_frame, | 468 const scoped_refptr<media::VideoFrame>& reserved_frame, |
| 469 int frame_rate, |
571 base::Time timestamp) { | 470 base::Time timestamp) { |
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
573 | 472 |
574 if (!buffer_pool_.get()) | |
575 return; | |
576 | |
577 int buffer_id = buffer_pool_->RecognizeReservedBuffer( | 473 int buffer_id = buffer_pool_->RecognizeReservedBuffer( |
578 reserved_frame->shared_memory_handle()); | 474 reserved_frame->shared_memory_handle()); |
579 if (buffer_id < 0) { | 475 if (buffer_id < 0) { |
580 NOTREACHED(); | 476 NOTREACHED(); |
581 return; | 477 return; |
582 } | 478 } |
583 | 479 |
| 480 media::VideoCaptureFormat frame_format( |
| 481 reserved_frame->coded_size().width(), |
| 482 reserved_frame->coded_size().height(), |
| 483 frame_rate, |
| 484 media::VariableResolutionVideoCaptureDevice); |
| 485 |
584 int count = 0; | 486 int count = 0; |
585 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 487 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
586 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 488 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
587 client_it != controller_clients_.end(); ++client_it) { | 489 client_it != controller_clients_.end(); ++client_it) { |
588 if ((*client_it)->session_closed) | 490 ControllerClient* client = *client_it; |
| 491 if (client->session_closed) |
589 continue; | 492 continue; |
590 | 493 |
591 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | 494 bool is_new_buffer = client->known_buffers.insert(buffer_id).second; |
592 buffer_id, timestamp); | 495 if (is_new_buffer) { |
593 (*client_it)->buffers.insert(buffer_id); | 496 // On the first use of a buffer on a client, share the memory handle. |
| 497 size_t memory_size = 0; |
| 498 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess( |
| 499 buffer_id, client->render_process_handle, &memory_size); |
| 500 client->event_handler->OnBufferCreated(client->controller_id, |
| 501 remote_handle, |
| 502 memory_size, |
| 503 buffer_id); |
| 504 } |
| 505 |
| 506 client->event_handler->OnBufferReady(client->controller_id, |
| 507 buffer_id, timestamp, |
| 508 frame_format); |
| 509 bool inserted = client->active_buffers.insert(buffer_id).second; |
| 510 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id; |
594 count++; | 511 count++; |
595 } | 512 } |
596 } | 513 } |
597 | 514 |
598 buffer_pool_->HoldForConsumers(buffer_id, count); | 515 buffer_pool_->HoldForConsumers(buffer_id, count); |
599 } | 516 } |
600 | 517 |
601 void VideoCaptureController::DoFrameInfoOnIOThread( | |
602 const media::VideoCaptureCapability& frame_info, | |
603 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) { | |
604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
605 DCHECK(!buffer_pool_.get()) << "Frame info should happen only once."; | |
606 | |
607 // Allocate memory only when device has been started. | |
608 if (state_ != VIDEO_CAPTURE_STATE_STARTED) | |
609 return; | |
610 | |
611 frame_info_ = frame_info; | |
612 buffer_pool_ = buffer_pool; | |
613 | |
614 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
615 client_it != controller_clients_.end(); ++client_it) { | |
616 if ((*client_it)->session_closed) | |
617 continue; | |
618 | |
619 SendFrameInfoAndBuffers(*client_it); | |
620 } | |
621 } | |
622 | |
623 void VideoCaptureController::DoFrameInfoChangedOnIOThread( | |
624 const media::VideoCaptureCapability& info) { | |
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
626 // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if | |
627 // needed, to support the new video capture format. See crbug.com/266082. | |
628 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
629 client_it != controller_clients_.end(); ++client_it) { | |
630 if ((*client_it)->session_closed) | |
631 continue; | |
632 | |
633 (*client_it)->event_handler->OnFrameInfoChanged( | |
634 (*client_it)->controller_id, | |
635 info.width, | |
636 info.height, | |
637 info.frame_rate); | |
638 } | |
639 } | |
640 | |
641 void VideoCaptureController::DoErrorOnIOThread() { | 518 void VideoCaptureController::DoErrorOnIOThread() { |
642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
643 state_ = VIDEO_CAPTURE_STATE_ERROR; | 520 state_ = VIDEO_CAPTURE_STATE_ERROR; |
644 ControllerClients::iterator client_it; | 521 |
645 for (client_it = controller_clients_.begin(); | 522 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
646 client_it != controller_clients_.end(); ++client_it) { | 523 client_it != controller_clients_.end(); ++client_it) { |
647 if ((*client_it)->session_closed) | 524 ControllerClient* client = *client_it; |
648 continue; | 525 if (client->session_closed) |
| 526 continue; |
649 | 527 |
650 (*client_it)->event_handler->OnError((*client_it)->controller_id); | 528 client->event_handler->OnError(client->controller_id); |
651 } | 529 } |
652 } | 530 } |
653 | 531 |
654 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { | 532 void VideoCaptureController::DoBufferDestroyedOnIOThread( |
| 533 int buffer_id_to_drop) { |
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
656 DCHECK(frame_info_.IsValid()); | |
657 client->event_handler->OnFrameInfo(client->controller_id, | |
658 frame_info_); | |
659 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { | |
660 base::SharedMemoryHandle remote_handle = | |
661 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); | |
662 | 535 |
663 client->event_handler->OnBufferCreated(client->controller_id, | 536 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
664 remote_handle, | 537 client_it != controller_clients_.end(); ++client_it) { |
665 buffer_pool_->GetMemorySize(), | 538 ControllerClient* client = *client_it; |
666 buffer_id); | 539 if (client->session_closed) |
| 540 continue; |
| 541 |
| 542 if (client->known_buffers.erase(buffer_id_to_drop)) { |
| 543 client->event_handler->OnBufferDestroyed(client->controller_id, |
| 544 buffer_id_to_drop); |
| 545 } |
667 } | 546 } |
668 } | 547 } |
669 | 548 |
670 VideoCaptureController::ControllerClient* | 549 VideoCaptureController::ControllerClient* |
671 VideoCaptureController::FindClient( | 550 VideoCaptureController::FindClient( |
672 const VideoCaptureControllerID& id, | 551 const VideoCaptureControllerID& id, |
673 VideoCaptureControllerEventHandler* handler, | 552 VideoCaptureControllerEventHandler* handler, |
674 const ControllerClients& clients) { | 553 const ControllerClients& clients) { |
675 for (ControllerClients::const_iterator client_it = clients.begin(); | 554 for (ControllerClients::const_iterator client_it = clients.begin(); |
676 client_it != clients.end(); ++client_it) { | 555 client_it != clients.end(); ++client_it) { |
(...skipping 17 matching lines...) Expand all Loading... |
694 } | 573 } |
695 return NULL; | 574 return NULL; |
696 } | 575 } |
697 | 576 |
698 int VideoCaptureController::GetClientCount() { | 577 int VideoCaptureController::GetClientCount() { |
699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
700 return controller_clients_.size(); | 579 return controller_clients_.size(); |
701 } | 580 } |
702 | 581 |
703 } // namespace content | 582 } // namespace content |
OLD | NEW |