video_capture_controller.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/media/video_capture_controller.h" 6 7#include <set> 8 9#include "base/bind.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/stl_util.h" 12#include "content/browser/renderer_host/media/media_stream_manager.h" 13#include "content/browser/renderer_host/media/video_capture_manager.h" 14#include "content/public/browser/browser_thread.h" 15#include "media/base/video_frame.h" 16#include "media/base/video_util.h" 17#include "media/base/yuv_convert.h" 18 19#if !defined(OS_IOS) && !defined(OS_ANDROID) 20#include "third_party/libyuv/include/libyuv.h" 21#endif 22 23namespace { 24 25// TODO(wjia): Support stride. 26void RotatePackedYV12Frame( 27 const uint8* src, 28 uint8* dest_yplane, 29 uint8* dest_uplane, 30 uint8* dest_vplane, 31 int width, 32 int height, 33 int rotation, 34 bool flip_vert, 35 bool flip_horiz) { 36 media::RotatePlaneByPixels( 37 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); 38 int y_size = width * height; 39 src += y_size; 40 media::RotatePlaneByPixels( 41 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); 42 src += y_size/4; 43 media::RotatePlaneByPixels( 44 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); 45} 46 47} // namespace 48 49namespace content { 50 51// The number of buffers that VideoCaptureBufferPool should allocate. 52static const int kNoOfBuffers = 3; 53 54struct VideoCaptureController::ControllerClient { 55 ControllerClient( 56 const VideoCaptureControllerID& id, 57 VideoCaptureControllerEventHandler* handler, 58 base::ProcessHandle render_process, 59 const media::VideoCaptureParams& params) 60 : controller_id(id), 61 event_handler(handler), 62 render_process_handle(render_process), 63 parameters(params), 64 session_closed(false) { 65 } 66 67 ~ControllerClient() {} 68 69 // ID used for identifying this object. 70 VideoCaptureControllerID controller_id; 71 VideoCaptureControllerEventHandler* event_handler; 72 73 // Handle to the render process that will receive the capture buffers. 74 base::ProcessHandle render_process_handle; 75 media::VideoCaptureParams parameters; 76 77 // Buffers used by this client. 78 std::set<int> buffers; 79 80 // State of capture session, controlled by VideoCaptureManager directly. 81 bool session_closed; 82}; 83 84VideoCaptureController::VideoCaptureController( 85 VideoCaptureManager* video_capture_manager) 86 : chopped_width_(0), 87 chopped_height_(0), 88 frame_info_available_(false), 89 video_capture_manager_(video_capture_manager), 90 device_in_use_(false), 91 state_(VIDEO_CAPTURE_STATE_STOPPED) { 92 memset(¤t_params_, 0, sizeof(current_params_)); 93} 94 95void VideoCaptureController::StartCapture( 96 const VideoCaptureControllerID& id, 97 VideoCaptureControllerEventHandler* event_handler, 98 base::ProcessHandle render_process, 99 const media::VideoCaptureParams& params) { 100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 101 DVLOG(1) << "VideoCaptureController::StartCapture, id " << id.device_id 102 << ", (" << params.width 103 << ", " << params.height 104 << ", " << params.frame_per_second 105 << ", " << params.session_id 106 << ")"; 107 108 // Signal error in case device is already in error state. 109 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { 110 event_handler->OnError(id); 111 return; 112 } 113 114 // Do nothing if this client has called StartCapture before. 115 if (FindClient(id, event_handler, controller_clients_) || 116 FindClient(id, event_handler, pending_clients_)) 117 return; 118 119 ControllerClient* client = new ControllerClient(id, event_handler, 120 render_process, params); 121 // In case capture has been started, need to check different conditions. 122 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 123 // TODO(wjia): Temporarily disable restarting till client supports resampling. 124#if 0 125 // This client has higher resolution than what is currently requested. 126 // Need restart capturing. 127 if (params.width > current_params_.width || 128 params.height > current_params_.height) { 129 video_capture_manager_->Stop(current_params_.session_id, 130 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); 131 frame_info_available_ = false; 132 state_ = VIDEO_CAPTURE_STATE_STOPPING; 133 pending_clients_.push_back(client); 134 return; 135 } 136#endif 137 138 // This client's resolution is no larger than what's currently requested. 139 // When frame_info has been returned by device, send them to client. 140 if (frame_info_available_) { 141 SendFrameInfoAndBuffers(client); 142 } 143 controller_clients_.push_back(client); 144 return; 145 } 146 147 // In case the device is in the middle of stopping, put the client in 148 // pending queue. 149 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { 150 pending_clients_.push_back(client); 151 return; 152 } 153 154 // Fresh start. 155 controller_clients_.push_back(client); 156 current_params_ = params; 157 // Order the manager to start the actual capture. 158 video_capture_manager_->Start(params, this); 159 state_ = VIDEO_CAPTURE_STATE_STARTED; 160 device_in_use_ = true; 161} 162 163void VideoCaptureController::StopCapture( 164 const VideoCaptureControllerID& id, 165 VideoCaptureControllerEventHandler* event_handler) { 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 167 DVLOG(1) << "VideoCaptureController::StopCapture, id " << id.device_id; 168 169 ControllerClient* client = FindClient(id, event_handler, pending_clients_); 170 // If the client is still in pending queue, just remove it. 171 if (client) { 172 pending_clients_.remove(client); 173 return; 174 } 175 176 client = FindClient(id, event_handler, controller_clients_); 177 if (!client) 178 return; 179 180 // Take back all buffers held by the |client|. 181 if (buffer_pool_.get()) { 182 for (std::set<int>::iterator buffer_it = client->buffers.begin(); 183 buffer_it != client->buffers.end(); 184 ++buffer_it) { 185 int buffer_id = *buffer_it; 186 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); 187 } 188 } 189 client->buffers.clear(); 190 191 int session_id = client->parameters.session_id; 192 delete client; 193 controller_clients_.remove(client); 194 195 // No more clients. Stop device. 196 if (controller_clients_.empty() && 197 (state_ == VIDEO_CAPTURE_STATE_STARTED || 198 state_ == VIDEO_CAPTURE_STATE_ERROR)) { 199 video_capture_manager_->Stop(session_id, 200 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); 201 frame_info_available_ = false; 202 state_ = VIDEO_CAPTURE_STATE_STOPPING; 203 } 204} 205 206void VideoCaptureController::StopSession( 207 int session_id) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 209 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id; 210 211 ControllerClient* client = FindClient(session_id, pending_clients_); 212 if (!client) 213 client = FindClient(session_id, controller_clients_); 214 215 if (client) { 216 client->session_closed = true; 217 client->event_handler->OnEnded(client->controller_id); 218 } 219} 220 221void VideoCaptureController::ReturnBuffer( 222 const VideoCaptureControllerID& id, 223 VideoCaptureControllerEventHandler* event_handler, 224 int buffer_id) { 225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 226 227 ControllerClient* client = FindClient(id, event_handler, 228 controller_clients_); 229 230 // If this buffer is not held by this client, or this client doesn't exist 231 // in controller, do nothing. 232 if (!client || 233 client->buffers.find(buffer_id) == client->buffers.end()) 234 return; 235 236 client->buffers.erase(buffer_id); 237 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); 238 239 // When all buffers have been returned by clients and device has been 240 // called to stop, check if restart is needed. This could happen when 241 // capture needs to be restarted due to resolution change. 242 if (!buffer_pool_->IsAnyBufferHeldForConsumers() && 243 state_ == VIDEO_CAPTURE_STATE_STOPPING) { 244 PostStopping(); 245 } 246} 247 248scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() { 249 base::AutoLock lock(buffer_pool_lock_); 250 if (!buffer_pool_.get()) 251 return NULL; 252 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, 253 frame_info_.height), 254 0); 255} 256 257// Implements VideoCaptureDevice::EventHandler. 258// OnIncomingCapturedFrame is called the thread running the capture device. 259// I.e.- DirectShow thread on windows and v4l2_thread on Linux. 260void VideoCaptureController::OnIncomingCapturedFrame( 261 const uint8* data, 262 int length, 263 base::Time timestamp, 264 int rotation, 265 bool flip_vert, 266 bool flip_horiz) { 267 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || 268 frame_info_.color == media::VideoCaptureCapability::kYV12 || 269 (rotation == 0 && !flip_vert && !flip_horiz)); 270 271 scoped_refptr<media::VideoFrame> dst; 272 { 273 base::AutoLock lock(buffer_pool_lock_); 274 if (!buffer_pool_.get()) 275 return; 276 dst = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, 277 frame_info_.height), 278 rotation); 279 } 280 281 if (!dst.get()) 282 return; 283 284 uint8* yplane = dst->data(media::VideoFrame::kYPlane); 285 uint8* uplane = dst->data(media::VideoFrame::kUPlane); 286 uint8* vplane = dst->data(media::VideoFrame::kVPlane); 287 288 // Do color conversion from the camera format to I420. 289 switch (frame_info_.color) { 290 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. 291 break; 292 case media::VideoCaptureCapability::kI420: 293 DCHECK(!chopped_width_ && !chopped_height_); 294 RotatePackedYV12Frame( 295 data, yplane, uplane, vplane, frame_info_.width, frame_info_.height, 296 rotation, flip_vert, flip_horiz); 297 break; 298 case media::VideoCaptureCapability::kYV12: 299 DCHECK(!chopped_width_ && !chopped_height_); 300 RotatePackedYV12Frame( 301 data, yplane, vplane, uplane, frame_info_.width, frame_info_.height, 302 rotation, flip_vert, flip_horiz); 303 break; 304 case media::VideoCaptureCapability::kNV21: 305 DCHECK(!chopped_width_ && !chopped_height_); 306 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, 307 frame_info_.height); 308 break; 309 case media::VideoCaptureCapability::kYUY2: 310 DCHECK(!chopped_width_ && !chopped_height_); 311 if (frame_info_.width * frame_info_.height * 2 != length) { 312 // If |length| of |data| does not match the expected width and height 313 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. 314 break; 315 } 316 317 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, 318 frame_info_.height); 319 break; 320 case media::VideoCaptureCapability::kRGB24: { 321 int ystride = frame_info_.width; 322 int uvstride = frame_info_.width / 2; 323#if defined(OS_WIN) // RGB on Windows start at the bottom line. 324 int rgb_stride = -3 * (frame_info_.width + chopped_width_); 325 const uint8* rgb_src = data + 3 * (frame_info_.width + chopped_width_) * 326 (frame_info_.height -1 + chopped_height_); 327#else 328 int rgb_stride = 3 * (frame_info_.width + chopped_width_); 329 const uint8* rgb_src = data; 330#endif 331 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, 332 frame_info_.width, frame_info_.height, 333 rgb_stride, ystride, uvstride); 334 break; 335 } 336 case media::VideoCaptureCapability::kARGB: 337 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, 338 frame_info_.height, 339 (frame_info_.width + chopped_width_) * 4, 340 frame_info_.width, frame_info_.width / 2); 341 break; 342#if !defined(OS_IOS) && !defined(OS_ANDROID) 343 case media::VideoCaptureCapability::kMJPEG: { 344 int yplane_stride = frame_info_.width; 345 int uv_plane_stride = (frame_info_.width + 1) / 2; 346 int crop_x = 0; 347 int crop_y = 0; 348 libyuv::ConvertToI420(data, length, yplane, yplane_stride, uplane, 349 uv_plane_stride, vplane, uv_plane_stride, crop_x, 350 crop_y, frame_info_.width, frame_info_.height, 351 frame_info_.width, frame_info_.height, 352 libyuv::kRotate0, libyuv::FOURCC_MJPG); 353 break; 354 } 355#endif 356 default: 357 NOTREACHED(); 358 } 359 360 BrowserThread::PostTask(BrowserThread::IO, 361 FROM_HERE, 362 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 363 this, dst, timestamp)); 364} 365 366// OnIncomingCapturedVideoFrame is called the thread running the capture device. 367void VideoCaptureController::OnIncomingCapturedVideoFrame( 368 const scoped_refptr<media::VideoFrame>& frame, 369 base::Time timestamp) { 370 371 scoped_refptr<media::VideoFrame> target; 372 { 373 base::AutoLock lock(buffer_pool_lock_); 374 375 if (!buffer_pool_.get()) 376 return; 377 378 // If this is a frame that belongs to the buffer pool, we can forward it 379 // directly to the IO thread and be done. 380 if (buffer_pool_->RecognizeReservedBuffer( 381 frame->shared_memory_handle()) >= 0) { 382 BrowserThread::PostTask(BrowserThread::IO, 383 FROM_HERE, 384 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 385 this, frame, timestamp)); 386 return; 387 } 388 // Otherwise, this is a frame that belongs to the caller, and we must copy 389 // it to a frame from the buffer pool. 390 target = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, 391 frame_info_.height), 392 0); 393 } 394 395 if (!target.get()) 396 return; 397 398 // Validate the inputs. 399 if (frame->coded_size() != target->coded_size()) 400 return; // Only exact copies are supported. 401 if (!(frame->format() == media::VideoFrame::I420 || 402 frame->format() == media::VideoFrame::YV12 || 403 frame->format() == media::VideoFrame::RGB32)) { 404 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; 405 return; 406 } 407 408 const int kYPlane = media::VideoFrame::kYPlane; 409 const int kUPlane = media::VideoFrame::kUPlane; 410 const int kVPlane = media::VideoFrame::kVPlane; 411 const int kAPlane = media::VideoFrame::kAPlane; 412 const int kRGBPlane = media::VideoFrame::kRGBPlane; 413 414 // Do color conversion from the camera format to I420. 415 switch (frame->format()) { 416#if defined(GOOGLE_TV) 417 case media::VideoFrame::HOLE: 418 // Fall-through to NOTREACHED() block. 419#endif 420 case media::VideoFrame::INVALID: 421 case media::VideoFrame::YV16: 422 case media::VideoFrame::EMPTY: 423 case media::VideoFrame::NATIVE_TEXTURE: { 424 NOTREACHED(); 425 break; 426 } 427 case media::VideoFrame::I420: 428 case media::VideoFrame::YV12: { 429 DCHECK(!chopped_width_ && !chopped_height_); 430 media::CopyYPlane(frame->data(kYPlane), 431 frame->stride(kYPlane), 432 frame->rows(kYPlane), 433 target.get()); 434 media::CopyUPlane(frame->data(kUPlane), 435 frame->stride(kUPlane), 436 frame->rows(kUPlane), 437 target.get()); 438 media::CopyVPlane(frame->data(kVPlane), 439 frame->stride(kVPlane), 440 frame->rows(kVPlane), 441 target.get()); 442 break; 443 } 444 case media::VideoFrame::YV12A: { 445 DCHECK(!chopped_width_ && !chopped_height_); 446 media::CopyYPlane(frame->data(kYPlane), 447 frame->stride(kYPlane), 448 frame->rows(kYPlane), 449 target.get()); 450 media::CopyUPlane(frame->data(kUPlane), 451 frame->stride(kUPlane), 452 frame->rows(kUPlane), 453 target.get()); 454 media::CopyVPlane(frame->data(kVPlane), 455 frame->stride(kVPlane), 456 frame->rows(kVPlane), 457 target.get()); 458 media::CopyAPlane(frame->data(kAPlane), 459 frame->stride(kAPlane), 460 frame->rows(kAPlane), 461 target.get()); 462 break; 463 } 464 case media::VideoFrame::RGB32: { 465 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), 466 target->data(kYPlane), 467 target->data(kUPlane), 468 target->data(kVPlane), 469 target->coded_size().width(), 470 target->coded_size().height(), 471 frame->stride(kRGBPlane), 472 target->stride(kYPlane), 473 target->stride(kUPlane)); 474 break; 475 } 476 } 477 478 BrowserThread::PostTask(BrowserThread::IO, 479 FROM_HERE, 480 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 481 this, target, timestamp)); 482} 483 484void VideoCaptureController::OnError() { 485 BrowserThread::PostTask(BrowserThread::IO, 486 FROM_HERE, 487 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); 488} 489 490void VideoCaptureController::OnFrameInfo( 491 const media::VideoCaptureCapability& info) { 492 frame_info_= info; 493 // Handle cases when |info| has odd numbers for width/height. 494 if (info.width & 1) { 495 --frame_info_.width; 496 chopped_width_ = 1; 497 } else { 498 chopped_width_ = 0; 499 } 500 if (info.height & 1) { 501 --frame_info_.height; 502 chopped_height_ = 1; 503 } else { 504 chopped_height_ = 0; 505 } 506 BrowserThread::PostTask(BrowserThread::IO, 507 FROM_HERE, 508 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this)); 509} 510 511VideoCaptureController::~VideoCaptureController() { 512 buffer_pool_ = NULL; // Release all buffers. 513 STLDeleteContainerPointers(controller_clients_.begin(), 514 controller_clients_.end()); 515 STLDeleteContainerPointers(pending_clients_.begin(), 516 pending_clients_.end()); 517} 518 519// Called by VideoCaptureManager when a device have been stopped. 520void VideoCaptureController::OnDeviceStopped() { 521 BrowserThread::PostTask(BrowserThread::IO, 522 FROM_HERE, 523 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); 524} 525 526void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( 527 const scoped_refptr<media::VideoFrame>& reserved_frame, 528 base::Time timestamp) { 529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 530 531 if (!buffer_pool_.get()) 532 return; 533 534 int buffer_id = buffer_pool_->RecognizeReservedBuffer( 535 reserved_frame->shared_memory_handle()); 536 if (buffer_id < 0) { 537 NOTREACHED(); 538 return; 539 } 540 541 int count = 0; 542 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 543 for (ControllerClients::iterator client_it = controller_clients_.begin(); 544 client_it != controller_clients_.end(); ++client_it) { 545 if ((*client_it)->session_closed) 546 continue; 547 548 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, 549 buffer_id, timestamp); 550 (*client_it)->buffers.insert(buffer_id); 551 count++; 552 } 553 } 554 555 buffer_pool_->HoldForConsumers(buffer_id, count); 556} 557 558void VideoCaptureController::DoFrameInfoOnIOThread() { 559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 560 DCHECK(!buffer_pool_.get()) 561 << "Device is restarted without releasing shared memory."; 562 563 // Allocate memory only when device has been started. 564 if (state_ != VIDEO_CAPTURE_STATE_STARTED) 565 return; 566 567 scoped_refptr<VideoCaptureBufferPool> buffer_pool = 568 new VideoCaptureBufferPool(frame_info_.width * frame_info_.height * 3 / 2, 569 kNoOfBuffers); 570 571 // Check whether all buffers were created successfully. 572 if (!buffer_pool->Allocate()) { 573 state_ = VIDEO_CAPTURE_STATE_ERROR; 574 for (ControllerClients::iterator client_it = controller_clients_.begin(); 575 client_it != controller_clients_.end(); ++client_it) { 576 (*client_it)->event_handler->OnError((*client_it)->controller_id); 577 } 578 return; 579 } 580 581 { 582 base::AutoLock lock(buffer_pool_lock_); 583 buffer_pool_ = buffer_pool; 584 } 585 frame_info_available_ = true; 586 587 for (ControllerClients::iterator client_it = controller_clients_.begin(); 588 client_it != controller_clients_.end(); ++client_it) { 589 SendFrameInfoAndBuffers(*client_it); 590 } 591} 592 593void VideoCaptureController::DoErrorOnIOThread() { 594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 595 state_ = VIDEO_CAPTURE_STATE_ERROR; 596 ControllerClients::iterator client_it; 597 for (client_it = controller_clients_.begin(); 598 client_it != controller_clients_.end(); ++client_it) { 599 (*client_it)->event_handler->OnError((*client_it)->controller_id); 600 } 601 for (client_it = pending_clients_.begin(); 602 client_it != pending_clients_.end(); ++client_it) { 603 (*client_it)->event_handler->OnError((*client_it)->controller_id); 604 } 605} 606 607void VideoCaptureController::DoDeviceStoppedOnIOThread() { 608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 609 device_in_use_ = false; 610 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { 611 PostStopping(); 612 } 613} 614 615void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { 616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 617 DCHECK(frame_info_available_); 618 client->event_handler->OnFrameInfo(client->controller_id, 619 frame_info_.width, frame_info_.height, 620 frame_info_.frame_rate); 621 if (!buffer_pool_.get()) 622 return; 623 624 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { 625 base::SharedMemoryHandle remote_handle = 626 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); 627 628 client->event_handler->OnBufferCreated(client->controller_id, 629 remote_handle, 630 buffer_pool_->GetMemorySize(), 631 buffer_id); 632 } 633} 634 635VideoCaptureController::ControllerClient* 636VideoCaptureController::FindClient( 637 const VideoCaptureControllerID& id, 638 VideoCaptureControllerEventHandler* handler, 639 const ControllerClients& clients) { 640 for (ControllerClients::const_iterator client_it = clients.begin(); 641 client_it != clients.end(); ++client_it) { 642 if ((*client_it)->controller_id == id && 643 (*client_it)->event_handler == handler) { 644 return *client_it; 645 } 646 } 647 return NULL; 648} 649 650VideoCaptureController::ControllerClient* 651VideoCaptureController::FindClient( 652 int session_id, 653 const ControllerClients& clients) { 654 for (ControllerClients::const_iterator client_it = clients.begin(); 655 client_it != clients.end(); ++client_it) { 656 if ((*client_it)->parameters.session_id == session_id) { 657 return *client_it; 658 } 659 } 660 return NULL; 661} 662 663// This function is called when all buffers have been returned to controller, 664// or when device is stopped. It decides whether the device needs to be 665// restarted. 666void VideoCaptureController::PostStopping() { 667 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 668 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); 669 670 // When clients still have some buffers, or device has not been stopped yet, 671 // do nothing. 672 if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) || 673 device_in_use_) 674 return; 675 676 { 677 base::AutoLock lock(buffer_pool_lock_); 678 buffer_pool_ = NULL; 679 } 680 681 // No more client. Therefore the controller is stopped. 682 if (controller_clients_.empty() && pending_clients_.empty()) { 683 state_ = VIDEO_CAPTURE_STATE_STOPPED; 684 return; 685 } 686 687 // Restart the device. 688 current_params_.width = 0; 689 current_params_.height = 0; 690 ControllerClients::iterator client_it; 691 for (client_it = controller_clients_.begin(); 692 client_it != controller_clients_.end(); ++client_it) { 693 if (current_params_.width < (*client_it)->parameters.width) 694 current_params_.width = (*client_it)->parameters.width; 695 if (current_params_.height < (*client_it)->parameters.height) 696 current_params_.height = (*client_it)->parameters.height; 697 } 698 for (client_it = pending_clients_.begin(); 699 client_it != pending_clients_.end(); ) { 700 if (current_params_.width < (*client_it)->parameters.width) 701 current_params_.width = (*client_it)->parameters.width; 702 if (current_params_.height < (*client_it)->parameters.height) 703 current_params_.height = (*client_it)->parameters.height; 704 controller_clients_.push_back((*client_it)); 705 pending_clients_.erase(client_it++); 706 } 707 // Request the manager to start the actual capture. 708 video_capture_manager_->Start(current_params_, this); 709 state_ = VIDEO_CAPTURE_STATE_STARTED; 710 device_in_use_ = true; 711} 712 713} // namespace content 714