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 23 namespace { 24 25 // TODO(wjia): Support stride. 26 void 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 49 namespace content { 50 51 // The number of buffers that VideoCaptureBufferPool should allocate. 52 static const int kNoOfBuffers = 3; 53 54 struct 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 84 VideoCaptureController::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 95 void 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 163 void 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 206 void 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 221 void 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 248 scoped_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. 260 void 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. 367 void 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 484 void VideoCaptureController::OnError() { 485 BrowserThread::PostTask(BrowserThread::IO, 486 FROM_HERE, 487 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); 488 } 489 490 void 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 511 void VideoCaptureController::OnFrameInfoChanged( 512 const media::VideoCaptureCapability& info) { 513 BrowserThread::PostTask(BrowserThread::IO, 514 FROM_HERE, 515 base::Bind(&VideoCaptureController::DoFrameInfoChangedOnIOThread, 516 this, info)); 517 } 518 519 VideoCaptureController::~VideoCaptureController() { 520 buffer_pool_ = NULL; // Release all buffers. 521 STLDeleteContainerPointers(controller_clients_.begin(), 522 controller_clients_.end()); 523 STLDeleteContainerPointers(pending_clients_.begin(), 524 pending_clients_.end()); 525 } 526 527 // Called by VideoCaptureManager when a device have been stopped. 528 void VideoCaptureController::OnDeviceStopped() { 529 BrowserThread::PostTask(BrowserThread::IO, 530 FROM_HERE, 531 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); 532 } 533 534 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( 535 const scoped_refptr<media::VideoFrame>& reserved_frame, 536 base::Time timestamp) { 537 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 538 539 if (!buffer_pool_.get()) 540 return; 541 542 int buffer_id = buffer_pool_->RecognizeReservedBuffer( 543 reserved_frame->shared_memory_handle()); 544 if (buffer_id < 0) { 545 NOTREACHED(); 546 return; 547 } 548 549 int count = 0; 550 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 551 for (ControllerClients::iterator client_it = controller_clients_.begin(); 552 client_it != controller_clients_.end(); ++client_it) { 553 if ((*client_it)->session_closed) 554 continue; 555 556 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, 557 buffer_id, timestamp); 558 (*client_it)->buffers.insert(buffer_id); 559 count++; 560 } 561 } 562 563 buffer_pool_->HoldForConsumers(buffer_id, count); 564 } 565 566 void VideoCaptureController::DoFrameInfoOnIOThread() { 567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 568 DCHECK(!buffer_pool_.get()) 569 << "Device is restarted without releasing shared memory."; 570 571 // Allocate memory only when device has been started. 572 if (state_ != VIDEO_CAPTURE_STATE_STARTED) 573 return; 574 575 scoped_refptr<VideoCaptureBufferPool> buffer_pool = 576 new VideoCaptureBufferPool(frame_info_.width * frame_info_.height * 3 / 2, 577 kNoOfBuffers); 578 579 // Check whether all buffers were created successfully. 580 if (!buffer_pool->Allocate()) { 581 state_ = VIDEO_CAPTURE_STATE_ERROR; 582 for (ControllerClients::iterator client_it = controller_clients_.begin(); 583 client_it != controller_clients_.end(); ++client_it) { 584 (*client_it)->event_handler->OnError((*client_it)->controller_id); 585 } 586 return; 587 } 588 589 { 590 base::AutoLock lock(buffer_pool_lock_); 591 buffer_pool_ = buffer_pool; 592 } 593 frame_info_available_ = true; 594 595 for (ControllerClients::iterator client_it = controller_clients_.begin(); 596 client_it != controller_clients_.end(); ++client_it) { 597 SendFrameInfoAndBuffers(*client_it); 598 } 599 } 600 601 void VideoCaptureController::DoFrameInfoChangedOnIOThread( 602 const media::VideoCaptureCapability& info) { 603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 604 // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if 605 // needed, to support the new video capture format. See crbug.com/266082. 606 for (ControllerClients::iterator client_it = controller_clients_.begin(); 607 client_it != controller_clients_.end(); ++client_it) { 608 (*client_it)->event_handler->OnFrameInfoChanged( 609 (*client_it)->controller_id, 610 info.width, 611 info.height, 612 info.frame_rate); 613 } 614 } 615 616 void VideoCaptureController::DoErrorOnIOThread() { 617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 618 state_ = VIDEO_CAPTURE_STATE_ERROR; 619 ControllerClients::iterator client_it; 620 for (client_it = controller_clients_.begin(); 621 client_it != controller_clients_.end(); ++client_it) { 622 (*client_it)->event_handler->OnError((*client_it)->controller_id); 623 } 624 for (client_it = pending_clients_.begin(); 625 client_it != pending_clients_.end(); ++client_it) { 626 (*client_it)->event_handler->OnError((*client_it)->controller_id); 627 } 628 } 629 630 void VideoCaptureController::DoDeviceStoppedOnIOThread() { 631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 632 device_in_use_ = false; 633 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { 634 PostStopping(); 635 } 636 } 637 638 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { 639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 640 DCHECK(frame_info_available_); 641 client->event_handler->OnFrameInfo(client->controller_id, 642 frame_info_); 643 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { 644 base::SharedMemoryHandle remote_handle = 645 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); 646 647 client->event_handler->OnBufferCreated(client->controller_id, 648 remote_handle, 649 buffer_pool_->GetMemorySize(), 650 buffer_id); 651 } 652 } 653 654 VideoCaptureController::ControllerClient* 655 VideoCaptureController::FindClient( 656 const VideoCaptureControllerID& id, 657 VideoCaptureControllerEventHandler* handler, 658 const ControllerClients& clients) { 659 for (ControllerClients::const_iterator client_it = clients.begin(); 660 client_it != clients.end(); ++client_it) { 661 if ((*client_it)->controller_id == id && 662 (*client_it)->event_handler == handler) { 663 return *client_it; 664 } 665 } 666 return NULL; 667 } 668 669 VideoCaptureController::ControllerClient* 670 VideoCaptureController::FindClient( 671 int session_id, 672 const ControllerClients& clients) { 673 for (ControllerClients::const_iterator client_it = clients.begin(); 674 client_it != clients.end(); ++client_it) { 675 if ((*client_it)->parameters.session_id == session_id) { 676 return *client_it; 677 } 678 } 679 return NULL; 680 } 681 682 // This function is called when all buffers have been returned to controller, 683 // or when device is stopped. It decides whether the device needs to be 684 // restarted. 685 void VideoCaptureController::PostStopping() { 686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 687 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); 688 689 // When clients still have some buffers, or device has not been stopped yet, 690 // do nothing. 691 if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) || 692 device_in_use_) 693 return; 694 695 { 696 base::AutoLock lock(buffer_pool_lock_); 697 buffer_pool_ = NULL; 698 } 699 700 // No more client. Therefore the controller is stopped. 701 if (controller_clients_.empty() && pending_clients_.empty()) { 702 state_ = VIDEO_CAPTURE_STATE_STOPPED; 703 return; 704 } 705 706 // Restart the device. 707 current_params_.width = 0; 708 current_params_.height = 0; 709 ControllerClients::iterator client_it; 710 for (client_it = controller_clients_.begin(); 711 client_it != controller_clients_.end(); ++client_it) { 712 if (current_params_.width < (*client_it)->parameters.width) 713 current_params_.width = (*client_it)->parameters.width; 714 if (current_params_.height < (*client_it)->parameters.height) 715 current_params_.height = (*client_it)->parameters.height; 716 } 717 for (client_it = pending_clients_.begin(); 718 client_it != pending_clients_.end(); ) { 719 if (current_params_.width < (*client_it)->parameters.width) 720 current_params_.width = (*client_it)->parameters.width; 721 if (current_params_.height < (*client_it)->parameters.height) 722 current_params_.height = (*client_it)->parameters.height; 723 controller_clients_.push_back((*client_it)); 724 pending_clients_.erase(client_it++); 725 } 726 // Request the manager to start the actual capture. 727 video_capture_manager_->Start(current_params_, this); 728 state_ = VIDEO_CAPTURE_STATE_STARTED; 729 device_in_use_ = true; 730 } 731 732 } // namespace content 733