Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(399)

Side by Side Diff: content/browser/renderer_host/media/video_capture_controller.cc

Issue 8304017: enable video capture to support sharing across multiple renderer processes (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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(&current_params_, 0, sizeof(current_params_));
27 memset(&params_, 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,
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 // This client has higher resolution than what is currently requested.
84 // Need restart capturing.
85 if (params.width > current_params_.width ||
86 params.height > current_params_.height) {
87 video_capture_manager_->Stop(current_params_.session_id,
88 base::Bind(&VideoCaptureController::OnDeviceStopped, this));
89 frame_info_available_ = false;
90 state_ = media::VideoCapture::kStopping;
91 pending_clients_.push_back(client);
92 return;
93 }
94
95 // This client's resolution is no larger than what's currently requested.
96 // When frame_info has been returned by device, send them to client.
97 if (frame_info_available_) {
98 SendFrameInfoAndBuffers(client);
99 }
100 controller_clients_.push_back(client);
101 return;
102 }
103
104 // In case the device is in the middle of stopping, put the client in
105 // pending queue.
106 if (state_ == media::VideoCapture::kStopping) {
107 pending_clients_.push_back(client);
108 return;
109 }
110
111 // Fresh start.
112 controller_clients_.push_back(client);
113 current_params_ = params;
41 // Order the manager to start the actual capture. 114 // Order the manager to start the actual capture.
42 video_capture_manager_->Start(params, this); 115 video_capture_manager_->Start(params, this);
43 } 116 state_ = media::VideoCapture::kStarted;
44 117 }
45 void VideoCaptureController::StopCapture(base::Closure stopped_cb) { 118
119 void VideoCaptureController::StopCapture(
120 const VideoCaptureControllerID& id,
121 VideoCaptureControllerEventHandler* event_handler,
122 bool force_buffer_return) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
47 124
48 video_capture_manager_->Stop(params_.session_id, 125 ControllerClients::iterator cit;
49 base::Bind(&VideoCaptureController::OnDeviceStopped, this, stopped_cb)); 126 cit = FindClient(id, event_handler, pending_clients_);
50 } 127 // If the client is still in pending queue, just remove it.
51 128 if (cit != pending_clients_.end()) {
52 void VideoCaptureController::ReturnBuffer(int buffer_id) { 129 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id);
130 pending_clients_.erase(cit);
131 return;
132 }
133
134 cit = FindClient(id, event_handler, controller_clients_);
135 // The client should have called StartCapture.
136 DCHECK(cit != controller_clients_.end());
137
138 if (force_buffer_return) {
139 // The client requests to return buffers which means it can't return
140 // buffers normally. After buffers are returned, client is free to
141 // delete itself. No need to call OnReadyToDelete.
142
143 // Return all buffers held by the clients.
144 for (std::list<int>::iterator bit = (*cit)->buffers.begin();
145 bit != (*cit)->buffers.end(); ++bit) {
146 int buffer_id = *bit;
147 ClientSideDIBCount::iterator dit = client_side_dib_count_.find(buffer_id);
148 if (dit == client_side_dib_count_.end())
149 continue;
150
151 if (--dit->second > 0)
152 continue;
153
154 // Now this |buffer_id| is not used by any client.
155 client_side_dib_count_.erase(buffer_id);
156 {
157 base::AutoLock lock(lock_);
158 free_dibs_.push_back(buffer_id);
159 }
160 }
161 (*cit)->buffers.clear();
162 } else {
163 // Normal way to stop capture.
164 if ((*cit)->buffers.size() > 0) {
165 // There are still some buffers held by the client.
166 (*cit)->report_ready_to_delete = true;
167 return;
168 }
169 // No buffer is held by the client. Ready to delete.
170 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id);
171 }
172
173 controller_clients_.erase(cit);
174
175 // No more clients. Stop device.
176 if (controller_clients_.size() == 0) {
177 video_capture_manager_->Stop(current_params_.session_id,
178 base::Bind(&VideoCaptureController::OnDeviceStopped, this));
179 frame_info_available_ = false;
180 state_ = media::VideoCapture::kStopping;
181 }
182 }
183
184 void VideoCaptureController::ReturnBuffer(
185 const VideoCaptureControllerID& id,
186 VideoCaptureControllerEventHandler* event_handler,
187 int buffer_id) {
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
54 189
55 bool ready_to_delete; 190 ControllerClients::iterator cit = FindClient(id, event_handler,
191 controller_clients_);
192 ClientSideDIBCount::iterator dit = client_side_dib_count_.find(buffer_id);
193 // If this buffer is not held by this client, or this client doesn't exist
194 // in controller, do nothing.
195 if (cit == controller_clients_.end() || dit == client_side_dib_count_.end())
196 return;
197
198 (*cit)->buffers.remove(buffer_id);
199 // If this client has called StopCapture and doesn't hold any buffer after
200 // after this return, ready to delet this client.
perkj_chrome 2011/10/28 08:37:19 nit delet -delete
wjia(left Chromium) 2011/10/29 02:34:40 Done.
201 if ((*cit)->report_ready_to_delete && (*cit)->buffers.size() == 0) {
202 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id);
203 controller_clients_.erase(cit);
204 }
205 if (--dit->second > 0)
206 return;
207
208 // Now this |buffer_id| is not used by any client.
209 client_side_dib_count_.erase(buffer_id);
56 { 210 {
57 base::AutoLock lock(lock_); 211 base::AutoLock lock(lock_);
58 free_dibs_.push_back(buffer_id); 212 free_dibs_.push_back(buffer_id);
59 ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && 213 }
60 report_ready_to_delete_; 214
61 } 215 // When all buffers have been returned by clients and device has been
62 if (ready_to_delete) { 216 // called to stop, check if restart is needed. This could happen when
63 event_handler_->OnReadyToDelete(id_); 217 // some clients call StopCapture before returning all buffers.
64 } 218 if (!ClientHasDIB() && state_ == media::VideoCapture::kStopping) {
65 } 219 PostStopping();
66 220 }
221 }
222
67 /////////////////////////////////////////////////////////////////////////////// 223 ///////////////////////////////////////////////////////////////////////////////
68 // Implements VideoCaptureDevice::EventHandler. 224 // Implements VideoCaptureDevice::EventHandler.
69 // OnIncomingCapturedFrame is called the thread running the capture device. 225 // OnIncomingCapturedFrame is called the thread running the capture device.
70 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. 226 // I.e.- DirectShow thread on windows and v4l2_thread on Linux.
71 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, 227 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data,
72 int length, 228 int length,
73 base::Time timestamp) { 229 base::Time timestamp) {
74 int buffer_id = 0; 230 int buffer_id = 0;
75 base::SharedMemory* dib = NULL; 231 base::SharedMemory* dib = NULL;
76 // Check if there is a TransportDIB to fill. 232 // Check if there is a DIB to fill.
77 bool buffer_exist = false; 233 bool buffer_exist = false;
78 { 234 {
79 base::AutoLock lock(lock_); 235 base::AutoLock lock(lock_);
80 if (!report_ready_to_delete_ && free_dibs_.size() > 0) { 236 if (free_dibs_.size() > 0) {
81 buffer_id = free_dibs_.front(); 237 buffer_id = free_dibs_.front();
82 free_dibs_.pop_front(); 238 free_dibs_.pop_front();
83 DIBMap::iterator it = owned_dibs_.find(buffer_id); 239 DIBMap::iterator it = owned_dibs_.find(buffer_id);
84 if (it != owned_dibs_.end()) { 240 if (it != owned_dibs_.end()) {
85 dib = it->second; 241 dib = it->second;
86 buffer_exist = true; 242 buffer_exist = true;
87 } 243 }
88 } 244 }
89 } 245 }
90 246
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; 299 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4;
144 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, 300 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width,
145 frame_info_.height, frame_info_.width * 4, 301 frame_info_.height, frame_info_.width * 4,
146 frame_info_.width, frame_info_.width / 2); 302 frame_info_.width, frame_info_.width / 2);
147 break; 303 break;
148 } 304 }
149 default: 305 default:
150 NOTREACHED(); 306 NOTREACHED();
151 } 307 }
152 308
153 event_handler_->OnBufferReady(id_, buffer_id, timestamp); 309 BrowserThread::PostTask(BrowserThread::IO,
310 FROM_HERE,
311 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
312 this, buffer_id, timestamp));
154 } 313 }
155 314
156 void VideoCaptureController::OnError() { 315 void VideoCaptureController::OnError() {
157 event_handler_->OnError(id_); 316 video_capture_manager_->Error(current_params_.session_id);
158 video_capture_manager_->Error(params_.session_id); 317 BrowserThread::PostTask(BrowserThread::IO,
318 FROM_HERE,
319 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this));
159 } 320 }
160 321
161 void VideoCaptureController::OnFrameInfo( 322 void VideoCaptureController::OnFrameInfo(
162 const media::VideoCaptureDevice::Capability& info) { 323 const media::VideoCaptureDevice::Capability& info) {
324 BrowserThread::PostTask(BrowserThread::IO,
325 FROM_HERE,
326 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread,
327 this, info));
328 }
329
330 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
331 int buffer_id, base::Time timestamp) {
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
333
334 if (state_ != media::VideoCapture::kStarted) {
335 base::AutoLock lock(lock_);
336 free_dibs_.push_back(buffer_id);
337 return;
338 }
339
340 int count = 0;
341 for (ControllerClients::iterator cit = controller_clients_.begin();
342 cit != controller_clients_.end(); cit++) {
343 if ((*cit)->report_ready_to_delete)
344 continue;
345
346 (*cit)->event_handler->OnBufferReady((*cit)->controller_id,
347 buffer_id, timestamp);
348 (*cit)->buffers.push_back(buffer_id);
349 count++;
350 }
351 if (count > 0) {
352 client_side_dib_count_[buffer_id] = count;
353 } else {
354 base::AutoLock lock(lock_);
355 free_dibs_.push_back(buffer_id);
356 }
357 }
358
359 void VideoCaptureController::DoErrorOnIOThread() {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
361 state_ = media::VideoCapture::kError;
362 ControllerClients::iterator cit;
363 for (cit = controller_clients_.begin();
364 cit != controller_clients_.end(); cit++) {
365 (*cit)->event_handler->OnError((*cit)->controller_id);
366 }
367 for (cit = pending_clients_.begin();
368 cit != pending_clients_.end(); cit++) {
369 (*cit)->event_handler->OnError((*cit)->controller_id);
370 }
371 }
372
373 void VideoCaptureController::DoFrameInfoOnIOThread(
374 const media::VideoCaptureDevice::Capability info) {
375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
163 DCHECK(owned_dibs_.empty()); 376 DCHECK(owned_dibs_.empty());
377
164 bool frames_created = true; 378 bool frames_created = true;
165 const size_t needed_size = (info.width * info.height * 3) / 2; 379 const size_t needed_size = (info.width * info.height * 3) / 2;
380 base::AutoLock lock(lock_);
166 for (size_t i = 1; i <= kNoOfDIBS; ++i) { 381 for (size_t i = 1; i <= kNoOfDIBS; ++i) {
167 base::SharedMemory* shared_memory = new base::SharedMemory(); 382 base::SharedMemory* shared_memory = new base::SharedMemory();
168 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { 383 if (!shared_memory->CreateAndMapAnonymous(needed_size)) {
169 frames_created = false; 384 frames_created = false;
170 break; 385 break;
171 } 386 }
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)); 387 owned_dibs_.insert(std::make_pair(i, shared_memory));
177 free_dibs_.push_back(i); 388 free_dibs_.push_back(i);
178 event_handler_->OnBufferCreated(id_, remote_handle, 389 }
179 static_cast<int>(needed_size), 390 // Check whether all DIBs were created successfully.
180 static_cast<int>(i)); 391 if (!frames_created) {
392 state_ = media::VideoCapture::kError;
393 for (ControllerClients::iterator cit = controller_clients_.begin();
394 cit != controller_clients_.end(); cit++) {
395 (*cit)->event_handler->OnError((*cit)->controller_id);
396 }
397 return;
181 } 398 }
182 frame_info_= info; 399 frame_info_= info;
perkj_chrome 2011/10/28 08:37:19 nit: do you really need both frame_info and frame_
wjia(left Chromium) 2011/10/29 02:34:40 Using frame_info_available is easy to read. Anothe
183 400 frame_info_available_ = true;
184 // Check that all DIBs where created successfully. 401
185 if (!frames_created) { 402 for (ControllerClients::iterator cit = controller_clients_.begin();
186 event_handler_->OnError(id_); 403 cit != controller_clients_.end(); cit++) {
187 } 404 SendFrameInfoAndBuffersWithLock((*cit), static_cast<int>(needed_size));
188 event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); 405 }
406 }
407
408 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
410 DCHECK(frame_info_available_);
411 const size_t needed_size = (frame_info_.width * frame_info_.height * 3) / 2;
412 base::AutoLock lock(lock_);
413 SendFrameInfoAndBuffersWithLock(client, static_cast<int>(needed_size));
414 }
415
416 void VideoCaptureController::SendFrameInfoAndBuffersWithLock(
417 ControllerClient* client, int needed_size) {
418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
419 DCHECK(frame_info_available_);
420 client->event_handler->OnFrameInfo(client->controller_id,
421 frame_info_.width, frame_info_.height,
422 frame_info_.frame_rate);
423 for (DIBMap::iterator dit = owned_dibs_.begin();
424 dit != owned_dibs_.end(); dit++) {
425 base::SharedMemory* shared_memory = dit->second;
426 int index = dit->first;
427 base::SharedMemoryHandle remote_handle;
428 shared_memory->ShareToProcess(client->render_process_handle,
429 &remote_handle);
430 client->event_handler->OnBufferCreated(client->controller_id,
431 remote_handle,
432 needed_size,
433 index);
434 }
435 }
436
437 void VideoCaptureController::PostStopping() {
perkj_chrome 2011/10/28 08:37:19 Add a comment about what this function do. And may
wjia(left Chromium) 2011/10/29 02:34:40 Comments added. This function indeed also puts con
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
439 DCHECK_EQ(state_, media::VideoCapture::kStopping);
440
441 if (ClientHasDIB() || device_in_use_)
442 return;
443
444 // It's safe to free all DIB's on IO thread since device won't send
445 // buffer over.
446 free_dibs_.clear();
447 STLDeleteValues(&owned_dibs_);
448
449 if (controller_clients_.size() + pending_clients_.size() == 0) {
450 state_ = media::VideoCapture::kStopped;
451 return;
452 }
453
454 // Restart the device.
455 current_params_.width = 0;
456 current_params_.height = 0;
457 ControllerClients::iterator cit;
458 for (cit = controller_clients_.begin();
459 cit != controller_clients_.end(); cit++) {
460 if (current_params_.width < (*cit)->parameters.width)
461 current_params_.width = (*cit)->parameters.width;
462 if (current_params_.height < (*cit)->parameters.height)
463 current_params_.height = (*cit)->parameters.height;
464 }
465 for (cit = pending_clients_.begin();
466 cit != pending_clients_.end(); ) {
467 if (current_params_.width < (*cit)->parameters.width)
468 current_params_.width = (*cit)->parameters.width;
469 if (current_params_.height < (*cit)->parameters.height)
470 current_params_.height = (*cit)->parameters.height;
471 controller_clients_.push_back((*cit));
472 pending_clients_.erase(cit++);
473 }
474 // Request the manager to start the actual capture.
475 video_capture_manager_->Start(current_params_, this);
476 state_ = media::VideoCapture::kStarted;
477 }
478
479 bool VideoCaptureController::ClientHasDIB() {
480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
481 for (ClientSideDIBCount::iterator dit = client_side_dib_count_.begin();
482 dit != client_side_dib_count_.end(); dit++) {
483 if (dit->second > 0)
484 return true;
485 }
486 return false;
487 }
488
489 VideoCaptureController::ControllerClients::iterator
490 VideoCaptureController::FindClient(
491 const VideoCaptureControllerID& id,
492 VideoCaptureControllerEventHandler* handler,
493 ControllerClients& clients) {
494 for (ControllerClients::iterator cit = clients.begin();
495 cit != clients.end(); cit++) {
496 if ((*cit)->controller_id == id && (*cit)->event_handler == handler) {
497 return cit;
498 }
499 }
500 return clients.end();
189 } 501 }
190 502
191 /////////////////////////////////////////////////////////////////////////////// 503 ///////////////////////////////////////////////////////////////////////////////
192 // Called by VideoCaptureManager when a device have been stopped. 504 // Called by VideoCaptureManager when a device have been stopped.
193 // This will report to the event handler that this object is ready to be deleted 505 void VideoCaptureController::OnDeviceStopped() {
194 // if all DIBS have been returned. 506 BrowserThread::PostTask(BrowserThread::IO,
perkj_chrome 2011/10/28 08:37:19 Make sure that this post in this class is moved to
wjia(left Chromium) 2011/10/29 02:34:40 Controller doesn't need to know what threads VCMan
195 void VideoCaptureController::OnDeviceStopped(base::Closure stopped_cb) { 507 FROM_HERE,
196 bool ready_to_delete_now; 508 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this));
197 509 }
198 { 510
199 base::AutoLock lock(lock_); 511 void VideoCaptureController::DoDeviceStoppedOnIOThread() {
200 // Set flag to indicate we need to report when all DIBs have been returned. 512 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
201 report_ready_to_delete_ = true; 513 device_in_use_ = false;
202 ready_to_delete_now = (free_dibs_.size() == owned_dibs_.size()); 514 if (state_ == media::VideoCapture::kStopping) {
203 } 515 PostStopping();
204 516 }
205 if (ready_to_delete_now) { 517 }
206 event_handler_->OnReadyToDelete(id_); 518
207 }
208
209 if (!stopped_cb.is_null())
210 stopped_cb.Run();
211 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698