OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "content/browser/browser_thread.h" | 9 #include "content/browser/browser_thread.h" |
10 #include "content/browser/renderer_host/media/media_stream_manager.h" | 10 #include "content/browser/renderer_host/media/media_stream_manager.h" |
11 #include "content/browser/renderer_host/media/video_capture_manager.h" | 11 #include "content/browser/renderer_host/media/video_capture_manager.h" |
12 #include "media/base/yuv_convert.h" | 12 #include "media/base/yuv_convert.h" |
13 | 13 |
14 // The number of TransportDIBs VideoCaptureController allocate. | 14 // The number of DIBs VideoCaptureController allocate. |
15 static const size_t kNoOfDIBS = 3; | 15 static const size_t kNoOfDIBS = 3; |
16 | 16 |
17 struct VideoCaptureController::ControllerClient { | |
18 ControllerClient( | |
19 const VideoCaptureControllerID& id, | |
20 VideoCaptureControllerEventHandler* handler, | |
21 base::ProcessHandle render_process, | |
22 const media::VideoCaptureParams& params) | |
23 : controller_id(id), | |
24 event_handler(handler), | |
25 render_process_handle(render_process), | |
26 parameters(params), | |
27 report_ready_to_delete(false) { | |
28 } | |
29 | |
30 ~ControllerClient() {} | |
31 | |
32 // ID used for identifying this object. | |
33 VideoCaptureControllerID controller_id; | |
34 VideoCaptureControllerEventHandler* event_handler; | |
35 // Handle to the render process that will receive the DIBs. | |
36 base::ProcessHandle render_process_handle; | |
37 const media::VideoCaptureParams parameters; | |
38 // Buffers used by this client. | |
39 std::list<int> buffers; | |
40 bool report_ready_to_delete; | |
41 }; | |
42 | |
17 VideoCaptureController::VideoCaptureController( | 43 VideoCaptureController::VideoCaptureController( |
18 const VideoCaptureControllerID& id, | |
19 base::ProcessHandle render_process, | |
20 VideoCaptureControllerEventHandler* event_handler, | |
21 media_stream::VideoCaptureManager* video_capture_manager) | 44 media_stream::VideoCaptureManager* video_capture_manager) |
22 : render_handle_(render_process), | 45 : frame_info_available_(false), |
23 report_ready_to_delete_(false), | 46 video_capture_manager_(video_capture_manager), |
24 event_handler_(event_handler), | 47 device_in_use_(false), |
25 id_(id), | 48 state_(media::VideoCapture::kStopped) { |
26 video_capture_manager_(video_capture_manager) { | 49 memset(¤t_params_, 0, sizeof(current_params_)); |
27 memset(¶ms_, 0, sizeof(params_)); | |
28 } | 50 } |
29 | 51 |
30 VideoCaptureController::~VideoCaptureController() { | 52 VideoCaptureController::~VideoCaptureController() { |
31 // Delete all TransportDIBs. | 53 // Delete all DIBs. |
32 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), | 54 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), |
33 owned_dibs_.end()); | 55 owned_dibs_.end()); |
56 STLDeleteContainerPointers(controller_clients_.begin(), | |
57 controller_clients_.end()); | |
34 } | 58 } |
35 | 59 |
36 void VideoCaptureController::StartCapture( | 60 void VideoCaptureController::StartCapture( |
61 const VideoCaptureControllerID& id, | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Q: What do you think about moving the resolution a
wjia(left Chromium)
2011/10/26 21:17:33
If we put start/stop logic in manager, we have to
| |
62 VideoCaptureControllerEventHandler* event_handler, | |
63 base::ProcessHandle render_process, | |
37 const media::VideoCaptureParams& params) { | 64 const media::VideoCaptureParams& params) { |
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
39 | 66 // Signal error in case device is already in error state. |
40 params_ = params; | 67 if (state_ == media::VideoCapture::kError) { |
68 event_handler->OnError(id); | |
69 return; | |
70 } | |
71 | |
72 // Do nothing if this client has called StartCapture before. | |
73 if (FindClient(id, event_handler, controller_clients_) != | |
74 controller_clients_.end() || | |
75 FindClient(id, event_handler, pending_clients_) != | |
76 pending_clients_.end()) | |
77 return; | |
78 | |
79 ControllerClient* client = new ControllerClient(id, event_handler, | |
80 render_process, params); | |
81 // In case capture has been started, need to check different condtions. | |
82 if (state_ == media::VideoCapture::kStarted) { | |
83 // When frame_info has not been returned by device, just wait in pending | |
84 // queue. | |
85 if (!frame_info_available_) { | |
86 pending_clients_.push_back(client); | |
87 return; | |
88 } | |
89 | |
90 // This client has higher resolution than what is currently delivered. | |
91 // Need restart catpuring. | |
92 // TODO(wjia): Query the max capability of device. If request is larger | |
93 // than max, there is no need to restart. | |
94 if (params.width > frame_info_.width || | |
95 params.height > frame_info_.height) { | |
96 video_capture_manager_->Stop(current_params_.session_id, base::Closure()); | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Q: When is this restarted? I didn't find a call to
wjia(left Chromium)
2011/10/26 21:17:33
The restart happens in PostStopping() call. That's
| |
97 frame_info_available_ = false; | |
98 state_ = media::VideoCapture::kStopping; | |
99 pending_clients_.push_back(client); | |
100 return; | |
101 } | |
102 | |
103 // This client's resolution is no larger than what's currently delivered. | |
104 // Send frame_info and initial buffers to the client. | |
105 SendFrameInfoAndBuffers(client); | |
106 controller_clients_.push_back(client); | |
107 return; | |
108 } | |
109 | |
110 // In case the device is in the middle of stopping, put the client in | |
111 // pending queue. | |
112 if (state_ == media::VideoCapture::kStopping) { | |
113 pending_clients_.push_back(client); | |
114 return; | |
115 } | |
116 | |
117 // Fresh start. | |
118 controller_clients_.push_back(client); | |
119 current_params_ = params; | |
41 // Order the manager to start the actual capture. | 120 // Order the manager to start the actual capture. |
42 video_capture_manager_->Start(params, this); | 121 video_capture_manager_->Start(params, this); |
43 } | 122 state_ = media::VideoCapture::kStarted; |
44 | 123 } |
45 void VideoCaptureController::StopCapture(base::Closure stopped_cb) { | 124 |
125 void VideoCaptureController::StopCapture( | |
126 const VideoCaptureControllerID& id, | |
127 VideoCaptureControllerEventHandler* event_handler, | |
128 bool force_buffer_return) { | |
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
47 | 130 |
48 video_capture_manager_->Stop(params_.session_id, | 131 ControllerClients::iterator cit; |
49 base::Bind(&VideoCaptureController::OnDeviceStopped, this, stopped_cb)); | 132 cit = FindClient(id, event_handler, pending_clients_); |
50 } | 133 // If the client is still in pending queue, just remove it. |
51 | 134 if (cit != pending_clients_.end()) { |
52 void VideoCaptureController::ReturnBuffer(int buffer_id) { | 135 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); |
136 pending_clients_.erase(cit); | |
137 return; | |
138 } | |
139 | |
140 cit = FindClient(id, event_handler, controller_clients_); | |
141 // The client should have called StartCapture. | |
142 DCHECK(cit != controller_clients_.end()); | |
143 | |
144 if (force_buffer_return) { | |
145 // The client requests to return buffers which means it can't return | |
146 // buffers normally. After buffers are returned, client is free to | |
147 // delete itself. No need to call OnReadyToDelete. | |
148 | |
149 // Return all buffers held by the clients. | |
150 for (std::list<int>::iterator bit = (*cit)->buffers.begin(); | |
151 bit != (*cit)->buffers.end(); ++bit) { | |
152 int buffer_id = *bit; | |
153 ClientSideDIBCount::iterator dit = client_side_dib_count_.find(buffer_id); | |
154 if (dit == client_side_dib_count_.end()) | |
155 continue; | |
156 | |
157 if (--dit->second > 0) | |
158 continue; | |
159 | |
160 // Now this |buffer_id| is not used by any client. | |
161 client_side_dib_count_.erase(buffer_id); | |
162 { | |
163 base::AutoLock lock(lock_); | |
164 free_dibs_.push_back(buffer_id); | |
165 } | |
166 } | |
167 (*cit)->buffers.clear(); | |
168 } else { | |
169 // Normal way to stop capture. | |
170 if ((*cit)->buffers.size() > 0) { | |
171 // There are still some buffers held by the client. | |
172 (*cit)->report_ready_to_delete = true; | |
173 return; | |
174 } | |
175 // No buffer is held by the client. Ready to delete. | |
176 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); | |
177 } | |
178 | |
179 controller_clients_.erase(cit); | |
180 | |
181 // No more clients. Stop device. | |
182 if (controller_clients_.size() == 0) { | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Can there be pending request we should check for,
wjia(left Chromium)
2011/10/26 21:17:33
StartCapture and StopCapture run on IO thread. The
| |
183 video_capture_manager_->Stop(current_params_.session_id, base::Closure()); | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Can you explain how the event is used here? Previo
wjia(left Chromium)
2011/10/26 21:17:33
Actually, this is a NULL callback. I looked at vid
perkj_chrome
2011/10/27 07:27:32
Please check again.
All platforms have synchronou
| |
184 frame_info_available_ = false; | |
185 state_ = media::VideoCapture::kStopping; | |
186 } | |
187 } | |
188 | |
189 void VideoCaptureController::ReturnBuffer( | |
190 const VideoCaptureControllerID& id, | |
191 VideoCaptureControllerEventHandler* event_handler, | |
192 int buffer_id) { | |
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
54 | 194 |
55 bool ready_to_delete; | 195 ControllerClients::iterator cit = FindClient(id, event_handler, |
196 controller_clients_); | |
197 ClientSideDIBCount::iterator dit = client_side_dib_count_.find(buffer_id); | |
198 // If this buffer is not held by this client, or this client doesn't exist | |
199 // in controller, do nothing. | |
200 if (cit == controller_clients_.end() || dit == client_side_dib_count_.end()) | |
201 return; | |
202 | |
203 (*cit)->buffers.remove(buffer_id); | |
204 // If this client has called StopCapture and doesn't hold any buffer after | |
205 // after this return, ready to delet this client. | |
206 if ((*cit)->report_ready_to_delete && (*cit)->buffers.size() == 0) { | |
207 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); | |
208 controller_clients_.erase(cit); | |
209 } | |
210 if (--dit->second > 0) | |
211 return; | |
212 | |
213 // Now this |buffer_id| is not used by any client. | |
214 client_side_dib_count_.erase(buffer_id); | |
56 { | 215 { |
57 base::AutoLock lock(lock_); | 216 base::AutoLock lock(lock_); |
58 free_dibs_.push_back(buffer_id); | 217 free_dibs_.push_back(buffer_id); |
59 ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && | 218 } |
60 report_ready_to_delete_; | 219 |
61 } | 220 // When all buffers have been returned by clients and device has been |
62 if (ready_to_delete) { | 221 // called to stop, check if restart is needed. This could happen when |
63 event_handler_->OnReadyToDelete(id_); | 222 // some clients call StopCapture before returning all buffers. |
64 } | 223 if (!ClientHasDIB() && state_ == media::VideoCapture::kStopping) { |
65 } | 224 PostStopping(); |
66 | 225 } |
226 } | |
227 | |
67 /////////////////////////////////////////////////////////////////////////////// | 228 /////////////////////////////////////////////////////////////////////////////// |
68 // Implements VideoCaptureDevice::EventHandler. | 229 // Implements VideoCaptureDevice::EventHandler. |
69 // OnIncomingCapturedFrame is called the thread running the capture device. | 230 // OnIncomingCapturedFrame is called the thread running the capture device. |
70 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 231 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
71 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | 232 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, |
72 int length, | 233 int length, |
73 base::Time timestamp) { | 234 base::Time timestamp) { |
74 int buffer_id = 0; | 235 int buffer_id = 0; |
75 base::SharedMemory* dib = NULL; | 236 base::SharedMemory* dib = NULL; |
76 // Check if there is a TransportDIB to fill. | 237 // Check if there is a DIB to fill. |
77 bool buffer_exist = false; | 238 bool buffer_exist = false; |
78 { | 239 { |
79 base::AutoLock lock(lock_); | 240 base::AutoLock lock(lock_); |
80 if (!report_ready_to_delete_ && free_dibs_.size() > 0) { | 241 if (free_dibs_.size() > 0) { |
81 buffer_id = free_dibs_.front(); | 242 buffer_id = free_dibs_.front(); |
82 free_dibs_.pop_front(); | 243 free_dibs_.pop_front(); |
83 DIBMap::iterator it = owned_dibs_.find(buffer_id); | 244 DIBMap::iterator it = owned_dibs_.find(buffer_id); |
84 if (it != owned_dibs_.end()) { | 245 if (it != owned_dibs_.end()) { |
85 dib = it->second; | 246 dib = it->second; |
86 buffer_exist = true; | 247 buffer_exist = true; |
87 } | 248 } |
88 } | 249 } |
89 } | 250 } |
90 | 251 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | 304 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
144 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 305 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
145 frame_info_.height, frame_info_.width * 4, | 306 frame_info_.height, frame_info_.width * 4, |
146 frame_info_.width, frame_info_.width / 2); | 307 frame_info_.width, frame_info_.width / 2); |
147 break; | 308 break; |
148 } | 309 } |
149 default: | 310 default: |
150 NOTREACHED(); | 311 NOTREACHED(); |
151 } | 312 } |
152 | 313 |
153 event_handler_->OnBufferReady(id_, buffer_id, timestamp); | 314 BrowserThread::PostTask(BrowserThread::IO, |
315 FROM_HERE, | |
316 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
317 this, buffer_id, timestamp)); | |
154 } | 318 } |
155 | 319 |
156 void VideoCaptureController::OnError() { | 320 void VideoCaptureController::OnError() { |
157 event_handler_->OnError(id_); | 321 video_capture_manager_->Error(current_params_.session_id); |
158 video_capture_manager_->Error(params_.session_id); | 322 BrowserThread::PostTask(BrowserThread::IO, |
323 FROM_HERE, | |
324 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | |
159 } | 325 } |
160 | 326 |
161 void VideoCaptureController::OnFrameInfo( | 327 void VideoCaptureController::OnFrameInfo( |
162 const media::VideoCaptureDevice::Capability& info) { | 328 const media::VideoCaptureDevice::Capability& info) { |
329 BrowserThread::PostTask(BrowserThread::IO, | |
330 FROM_HERE, | |
331 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, | |
332 this, info)); | |
333 } | |
334 | |
335 void VideoCaptureController::OnDeviceState(bool in_use) { | |
336 BrowserThread::PostTask(BrowserThread::IO, | |
337 FROM_HERE, | |
338 base::Bind(&VideoCaptureController::DoDeviceStateOnIOThread, this, | |
339 in_use)); | |
340 } | |
341 | |
342 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | |
343 int buffer_id, base::Time timestamp) { | |
344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
345 | |
346 if (state_ != media::VideoCapture::kStarted) { | |
347 base::AutoLock lock(lock_); | |
348 free_dibs_.push_back(buffer_id); | |
349 return; | |
350 } | |
351 | |
352 int count = 0; | |
353 for (ControllerClients::iterator cit = controller_clients_.begin(); | |
354 cit != controller_clients_.end(); cit++) { | |
355 if ((*cit)->report_ready_to_delete) | |
356 continue; | |
357 | |
358 (*cit)->event_handler->OnBufferReady((*cit)->controller_id, | |
359 buffer_id, timestamp); | |
360 (*cit)->buffers.push_back(buffer_id); | |
361 count++; | |
362 } | |
363 if (count > 0) { | |
364 client_side_dib_count_[buffer_id] = count; | |
365 } else { | |
366 base::AutoLock lock(lock_); | |
367 free_dibs_.push_back(buffer_id); | |
368 } | |
369 } | |
370 | |
371 void VideoCaptureController::DoErrorOnIOThread() { | |
372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
373 state_ = media::VideoCapture::kError; | |
374 ControllerClients::iterator cit; | |
375 for (cit = controller_clients_.begin(); | |
376 cit != controller_clients_.end(); cit++) { | |
377 (*cit)->event_handler->OnError((*cit)->controller_id); | |
378 } | |
379 for (cit = pending_clients_.begin(); | |
380 cit != pending_clients_.end(); cit++) { | |
381 (*cit)->event_handler->OnError((*cit)->controller_id); | |
382 } | |
383 } | |
384 | |
385 void VideoCaptureController::DoDeviceStateOnIOThread(bool device_in_use) { | |
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
387 device_in_use_ = device_in_use; | |
388 video_capture_manager_->DeviceStatusFromController(this, device_in_use); | |
389 if (!device_in_use && state_ == media::VideoCapture::kStopping) { | |
390 PostStopping(); | |
391 } | |
392 } | |
393 | |
394 void VideoCaptureController::DoFrameInfoOnIOThread( | |
395 const media::VideoCaptureDevice::Capability info) { | |
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
163 DCHECK(owned_dibs_.empty()); | 397 DCHECK(owned_dibs_.empty()); |
398 | |
399 // Check if pending clients request higher resolution. | |
400 current_params_.width = info.width; | |
401 current_params_.height = info.height; | |
402 current_params_.frame_per_second = info.frame_rate; | |
403 ControllerClients::iterator cit; | |
404 for (cit = pending_clients_.begin(); | |
405 cit != pending_clients_.end(); ) { | |
406 if (current_params_.width < (*cit)->parameters.width) | |
407 current_params_.width = (*cit)->parameters.width; | |
408 if (current_params_.height < (*cit)->parameters.height) | |
409 current_params_.height = (*cit)->parameters.height; | |
410 controller_clients_.push_back((*cit)); | |
411 pending_clients_.erase(cit++); | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Doesn't this invalidate the list iterator and shou
wjia(left Chromium)
2011/10/26 21:17:33
This line is equivalent to
{
ControllerClients::it
| |
412 } | |
413 if (current_params_.width > info.width || | |
mflodman_chromium_OOO
2011/10/26 12:34:45
I'd like a comment to explain when this is happeni
wjia(left Chromium)
2011/10/26 21:17:33
Done.
| |
414 current_params_.height > info.height) { | |
415 video_capture_manager_->Stop(current_params_.session_id, base::Closure()); | |
416 frame_info_available_ = false; | |
417 state_ = media::VideoCapture::kStopping; | |
418 return; | |
419 } | |
420 | |
164 bool frames_created = true; | 421 bool frames_created = true; |
165 const size_t needed_size = (info.width * info.height * 3) / 2; | 422 const size_t needed_size = (info.width * info.height * 3) / 2; |
423 base::AutoLock lock(lock_); | |
166 for (size_t i = 1; i <= kNoOfDIBS; ++i) { | 424 for (size_t i = 1; i <= kNoOfDIBS; ++i) { |
167 base::SharedMemory* shared_memory = new base::SharedMemory(); | 425 base::SharedMemory* shared_memory = new base::SharedMemory(); |
168 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { | 426 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { |
169 frames_created = false; | 427 frames_created = false; |
170 break; | 428 break; |
171 } | 429 } |
172 base::SharedMemoryHandle remote_handle; | |
173 shared_memory->ShareToProcess(render_handle_, &remote_handle); | |
174 | |
175 base::AutoLock lock(lock_); | |
176 owned_dibs_.insert(std::make_pair(i, shared_memory)); | 430 owned_dibs_.insert(std::make_pair(i, shared_memory)); |
177 free_dibs_.push_back(i); | 431 free_dibs_.push_back(i); |
178 event_handler_->OnBufferCreated(id_, remote_handle, | 432 } |
179 static_cast<int>(needed_size), | 433 // Check whether all DIBs were created successfully. |
180 static_cast<int>(i)); | 434 if (!frames_created) { |
435 state_ = media::VideoCapture::kError; | |
436 for (ControllerClients::iterator it = controller_clients_.begin(); | |
437 it != controller_clients_.end(); it++) { | |
438 (*it)->event_handler->OnError((*it)->controller_id); | |
439 } | |
440 return; | |
181 } | 441 } |
182 frame_info_= info; | 442 frame_info_= info; |
183 | 443 frame_info_available_ = true; |
184 // Check that all DIBs where created successfully. | 444 |
185 if (!frames_created) { | 445 for (cit = controller_clients_.begin(); |
186 event_handler_->OnError(id_); | 446 cit != controller_clients_.end(); cit++) { |
187 } | 447 SendFrameInfoAndBuffersWithLock((*cit), static_cast<int>(needed_size)); |
188 event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); | 448 } |
189 } | 449 } |
190 | 450 |
191 /////////////////////////////////////////////////////////////////////////////// | 451 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { |
192 // Called by VideoCaptureManager when a device have been stopped. | 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
193 // This will report to the event handler that this object is ready to be deleted | 453 DCHECK(frame_info_available_); |
194 // if all DIBS have been returned. | 454 const size_t needed_size = (frame_info_.width * frame_info_.height * 3) / 2; |
195 void VideoCaptureController::OnDeviceStopped(base::Closure stopped_cb) { | 455 base::AutoLock lock(lock_); |
196 bool ready_to_delete_now; | 456 SendFrameInfoAndBuffersWithLock(client, static_cast<int>(needed_size)); |
197 | 457 } |
198 { | 458 |
199 base::AutoLock lock(lock_); | 459 void VideoCaptureController::SendFrameInfoAndBuffersWithLock( |
200 // Set flag to indicate we need to report when all DIBs have been returned. | 460 ControllerClient* client, int needed_size) { |
201 report_ready_to_delete_ = true; | 461 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
202 ready_to_delete_now = (free_dibs_.size() == owned_dibs_.size()); | 462 DCHECK(frame_info_available_); |
203 } | 463 client->event_handler->OnFrameInfo(client->controller_id, |
204 | 464 frame_info_.width, frame_info_.height, |
205 if (ready_to_delete_now) { | 465 frame_info_.frame_rate); |
206 event_handler_->OnReadyToDelete(id_); | 466 for (DIBMap::iterator dit = owned_dibs_.begin(); |
207 } | 467 dit != owned_dibs_.end(); dit++) { |
208 | 468 base::SharedMemory* shared_memory = dit->second; |
209 if (!stopped_cb.is_null()) | 469 int index = dit->first; |
210 stopped_cb.Run(); | 470 base::SharedMemoryHandle remote_handle; |
211 } | 471 shared_memory->ShareToProcess(client->render_process_handle, |
472 &remote_handle); | |
473 client->event_handler->OnBufferCreated(client->controller_id, | |
474 remote_handle, | |
475 needed_size, | |
476 index); | |
477 } | |
478 } | |
479 | |
480 void VideoCaptureController::PostStopping() { | |
481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
482 DCHECK_EQ(state_, media::VideoCapture::kStopping); | |
483 | |
484 if (ClientHasDIB() || device_in_use_) | |
485 return; | |
486 | |
487 // It's safe to free all DIB's on IO thread since device won't send | |
488 // buffer over. | |
489 free_dibs_.clear(); | |
490 STLDeleteValues(&owned_dibs_); | |
491 | |
492 if (controller_clients_.size() + pending_clients_.size() == 0) { | |
493 state_ = media::VideoCapture::kStopped; | |
494 return; | |
495 } | |
496 | |
497 // Restart the device. | |
498 current_params_.width = 0; | |
499 current_params_.height = 0; | |
500 ControllerClients::iterator cit; | |
501 for (cit = controller_clients_.begin(); | |
502 cit != controller_clients_.end(); cit++) { | |
503 if (current_params_.width < (*cit)->parameters.width) | |
504 current_params_.width = (*cit)->parameters.width; | |
505 if (current_params_.height < (*cit)->parameters.height) | |
506 current_params_.height = (*cit)->parameters.height; | |
507 } | |
508 for (cit = pending_clients_.begin(); | |
509 cit != pending_clients_.end(); ) { | |
510 if (current_params_.width < (*cit)->parameters.width) | |
511 current_params_.width = (*cit)->parameters.width; | |
512 if (current_params_.height < (*cit)->parameters.height) | |
513 current_params_.height = (*cit)->parameters.height; | |
514 controller_clients_.push_back((*cit)); | |
515 pending_clients_.erase(cit++); | |
mflodman_chromium_OOO
2011/10/26 12:34:45
Same comment about iterator as above.
wjia(left Chromium)
2011/10/26 21:17:33
Same explanation as above. :-)
| |
516 } | |
517 // Request the manager to start the actual capture. | |
518 video_capture_manager_->Start(current_params_, this); | |
519 state_ = media::VideoCapture::kStarted; | |
520 } | |
521 | |
522 bool VideoCaptureController::ClientHasDIB() { | |
523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
524 for (ClientSideDIBCount::iterator dit = client_side_dib_count_.begin(); | |
525 dit != client_side_dib_count_.end(); dit++) { | |
526 if (dit->second > 0) | |
527 return true; | |
528 } | |
529 return false; | |
530 } | |
531 | |
532 VideoCaptureController::ControllerClients::iterator | |
533 VideoCaptureController::FindClient( | |
534 const VideoCaptureControllerID& id, | |
535 VideoCaptureControllerEventHandler* handler, | |
536 ControllerClients& clients) { | |
537 for (ControllerClients::iterator cit = clients.begin(); | |
538 cit != clients.end(); cit++) { | |
539 if ((*cit)->controller_id == id && (*cit)->event_handler == handler) { | |
540 return cit; | |
541 } | |
542 } | |
543 return clients.end(); | |
544 } | |
545 | |
OLD | NEW |