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 <map> 8 #include <set> 9 10 #include "base/bind.h" 11 #include "base/debug/trace_event.h" 12 #include "base/metrics/histogram.h" 13 #include "base/metrics/sparse_histogram.h" 14 #include "base/stl_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "content/browser/renderer_host/media/media_stream_manager.h" 17 #include "content/browser/renderer_host/media/video_capture_manager.h" 18 #include "content/common/gpu/client/gl_helper.h" 19 #include "content/public/browser/browser_thread.h" 20 #include "gpu/command_buffer/common/mailbox_holder.h" 21 #include "media/base/video_frame.h" 22 #include "media/base/video_util.h" 23 #include "media/base/yuv_convert.h" 24 #include "third_party/libyuv/include/libyuv.h" 25 26 #if defined(OS_ANDROID) 27 #include "content/browser/renderer_host/image_transport_factory_android.h" 28 #else 29 #include "content/browser/compositor/image_transport_factory.h" 30 #endif 31 32 using media::VideoCaptureFormat; 33 34 namespace content { 35 36 namespace { 37 38 static const int kInfiniteRatio = 99999; 39 40 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \ 41 UMA_HISTOGRAM_SPARSE_SLOWLY( \ 42 name, \ 43 (height) ? ((width) * 100) / (height) : kInfiniteRatio); 44 45 class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer { 46 public: 47 PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, 48 int buffer_id, 49 void* data, 50 size_t size) 51 : Buffer(buffer_id, data, size), pool_(pool) { 52 DCHECK(pool_.get()); 53 } 54 55 private: 56 virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); } 57 58 const scoped_refptr<VideoCaptureBufferPool> pool_; 59 }; 60 61 class SyncPointClientImpl : public media::VideoFrame::SyncPointClient { 62 public: 63 explicit SyncPointClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {} 64 virtual ~SyncPointClientImpl() {} 65 virtual uint32 InsertSyncPoint() OVERRIDE { 66 return gl_helper_->InsertSyncPoint(); 67 } 68 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE { 69 gl_helper_->WaitSyncPoint(sync_point); 70 } 71 72 private: 73 GLHelper* gl_helper_; 74 }; 75 76 void ReturnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame, 77 uint32 sync_point) { 78 DCHECK_CURRENTLY_ON(BrowserThread::UI); 79 #if defined(OS_ANDROID) 80 GLHelper* gl_helper = 81 ImageTransportFactoryAndroid::GetInstance()->GetGLHelper(); 82 #else 83 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); 84 #endif 85 DCHECK(gl_helper); 86 // UpdateReleaseSyncPoint() creates a new sync_point using |gl_helper|, so 87 // wait the given |sync_point| using |gl_helper|. 88 gl_helper->WaitSyncPoint(sync_point); 89 SyncPointClientImpl client(gl_helper); 90 video_frame->UpdateReleaseSyncPoint(&client); 91 } 92 93 } // anonymous namespace 94 95 struct VideoCaptureController::ControllerClient { 96 ControllerClient(const VideoCaptureControllerID& id, 97 VideoCaptureControllerEventHandler* handler, 98 base::ProcessHandle render_process, 99 media::VideoCaptureSessionId session_id, 100 const media::VideoCaptureParams& params) 101 : controller_id(id), 102 event_handler(handler), 103 render_process_handle(render_process), 104 session_id(session_id), 105 parameters(params), 106 session_closed(false), 107 paused(false) {} 108 109 ~ControllerClient() {} 110 111 // ID used for identifying this object. 112 const VideoCaptureControllerID controller_id; 113 VideoCaptureControllerEventHandler* const event_handler; 114 115 // Handle to the render process that will receive the capture buffers. 116 const base::ProcessHandle render_process_handle; 117 const media::VideoCaptureSessionId session_id; 118 const media::VideoCaptureParams parameters; 119 120 // Buffers that are currently known to this client. 121 std::set<int> known_buffers; 122 123 // Buffers currently held by this client, and syncpoint callback to call when 124 // they are returned from the client. 125 typedef std::map<int, scoped_refptr<media::VideoFrame> > ActiveBufferMap; 126 ActiveBufferMap active_buffers; 127 128 // State of capture session, controlled by VideoCaptureManager directly. This 129 // transitions to true as soon as StopSession() occurs, at which point the 130 // client is sent an OnEnded() event. However, because the client retains a 131 // VideoCaptureController* pointer, its ControllerClient entry lives on until 132 // it unregisters itself via RemoveClient(), which may happen asynchronously. 133 // 134 // TODO(nick): If we changed the semantics of VideoCaptureHost so that 135 // OnEnded() events were processed synchronously (with the RemoveClient() done 136 // implicitly), we could avoid tracking this state here in the Controller, and 137 // simplify the code in both places. 138 bool session_closed; 139 140 // Indicates whether the client is paused, if true, VideoCaptureController 141 // stops updating its buffer. 142 bool paused; 143 }; 144 145 // Receives events from the VideoCaptureDevice and posts them to a 146 // VideoCaptureController on the IO thread. An instance of this class may safely 147 // outlive its target VideoCaptureController. 148 // 149 // Methods of this class may be called from any thread, and in practice will 150 // often be called on some auxiliary thread depending on the platform and the 151 // device type; including, for example, the DirectShow thread on Windows, the 152 // v4l2_thread on Linux, and the UI thread for tab capture. 153 class VideoCaptureController::VideoCaptureDeviceClient 154 : public media::VideoCaptureDevice::Client { 155 public: 156 explicit VideoCaptureDeviceClient( 157 const base::WeakPtr<VideoCaptureController>& controller, 158 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); 159 virtual ~VideoCaptureDeviceClient(); 160 161 // VideoCaptureDevice::Client implementation. 162 virtual scoped_refptr<Buffer> ReserveOutputBuffer( 163 media::VideoFrame::Format format, 164 const gfx::Size& size) OVERRIDE; 165 virtual void OnIncomingCapturedData(const uint8* data, 166 int length, 167 const VideoCaptureFormat& frame_format, 168 int rotation, 169 base::TimeTicks timestamp) OVERRIDE; 170 virtual void OnIncomingCapturedVideoFrame( 171 const scoped_refptr<Buffer>& buffer, 172 const VideoCaptureFormat& buffer_format, 173 const scoped_refptr<media::VideoFrame>& frame, 174 base::TimeTicks timestamp) OVERRIDE; 175 virtual void OnError(const std::string& reason) OVERRIDE; 176 virtual void OnLog(const std::string& message) OVERRIDE; 177 178 private: 179 scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format, 180 const gfx::Size& dimensions); 181 182 // The controller to which we post events. 183 const base::WeakPtr<VideoCaptureController> controller_; 184 185 // The pool of shared-memory buffers used for capturing. 186 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; 187 }; 188 189 VideoCaptureController::VideoCaptureController(int max_buffers) 190 : buffer_pool_(new VideoCaptureBufferPool(max_buffers)), 191 state_(VIDEO_CAPTURE_STATE_STARTED), 192 frame_received_(false), 193 weak_ptr_factory_(this) { 194 } 195 196 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( 197 const base::WeakPtr<VideoCaptureController>& controller, 198 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) 199 : controller_(controller), buffer_pool_(buffer_pool) {} 200 201 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} 202 203 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { 204 return weak_ptr_factory_.GetWeakPtr(); 205 } 206 207 scoped_ptr<media::VideoCaptureDevice::Client> 208 VideoCaptureController::NewDeviceClient() { 209 scoped_ptr<media::VideoCaptureDevice::Client> result( 210 new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_)); 211 return result.Pass(); 212 } 213 214 void VideoCaptureController::AddClient( 215 const VideoCaptureControllerID& id, 216 VideoCaptureControllerEventHandler* event_handler, 217 base::ProcessHandle render_process, 218 media::VideoCaptureSessionId session_id, 219 const media::VideoCaptureParams& params) { 220 DCHECK_CURRENTLY_ON(BrowserThread::IO); 221 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id 222 << ", " << params.requested_format.frame_size.ToString() 223 << ", " << params.requested_format.frame_rate 224 << ", " << session_id 225 << ")"; 226 227 // If this is the first client added to the controller, cache the parameters. 228 if (!controller_clients_.size()) 229 video_capture_format_ = params.requested_format; 230 231 // Signal error in case device is already in error state. 232 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { 233 event_handler->OnError(id); 234 return; 235 } 236 237 // Do nothing if this client has called AddClient before. 238 if (FindClient(id, event_handler, controller_clients_)) 239 return; 240 241 ControllerClient* client = new ControllerClient( 242 id, event_handler, render_process, session_id, params); 243 // If we already have gotten frame_info from the device, repeat it to the new 244 // client. 245 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 246 controller_clients_.push_back(client); 247 return; 248 } 249 } 250 251 int VideoCaptureController::RemoveClient( 252 const VideoCaptureControllerID& id, 253 VideoCaptureControllerEventHandler* event_handler) { 254 DCHECK_CURRENTLY_ON(BrowserThread::IO); 255 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id; 256 257 ControllerClient* client = FindClient(id, event_handler, controller_clients_); 258 if (!client) 259 return kInvalidMediaCaptureSessionId; 260 261 // Take back all buffers held by the |client|. 262 for (ControllerClient::ActiveBufferMap::iterator buffer_it = 263 client->active_buffers.begin(); 264 buffer_it != client->active_buffers.end(); 265 ++buffer_it) { 266 buffer_pool_->RelinquishConsumerHold(buffer_it->first, 1); 267 } 268 client->active_buffers.clear(); 269 270 int session_id = client->session_id; 271 controller_clients_.remove(client); 272 delete client; 273 274 return session_id; 275 } 276 277 void VideoCaptureController::PauseOrResumeClient( 278 const VideoCaptureControllerID& id, 279 VideoCaptureControllerEventHandler* event_handler, 280 bool pause) { 281 DCHECK_CURRENTLY_ON(BrowserThread::IO); 282 DVLOG(1) << "VideoCaptureController::PauseOrResumeClient, id " 283 << id.device_id << ", " << pause; 284 285 ControllerClient* client = FindClient(id, event_handler, controller_clients_); 286 if (!client) 287 return; 288 289 DCHECK(client->paused != pause); 290 client->paused = pause; 291 } 292 293 void VideoCaptureController::StopSession(int session_id) { 294 DCHECK_CURRENTLY_ON(BrowserThread::IO); 295 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id; 296 297 ControllerClient* client = FindClient(session_id, controller_clients_); 298 299 if (client) { 300 client->session_closed = true; 301 client->event_handler->OnEnded(client->controller_id); 302 } 303 } 304 305 void VideoCaptureController::ReturnBuffer( 306 const VideoCaptureControllerID& id, 307 VideoCaptureControllerEventHandler* event_handler, 308 int buffer_id, 309 uint32 sync_point) { 310 DCHECK_CURRENTLY_ON(BrowserThread::IO); 311 312 ControllerClient* client = FindClient(id, event_handler, controller_clients_); 313 314 // If this buffer is not held by this client, or this client doesn't exist 315 // in controller, do nothing. 316 ControllerClient::ActiveBufferMap::iterator iter; 317 if (!client || (iter = client->active_buffers.find(buffer_id)) == 318 client->active_buffers.end()) { 319 NOTREACHED(); 320 return; 321 } 322 scoped_refptr<media::VideoFrame> frame = iter->second; 323 client->active_buffers.erase(iter); 324 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); 325 326 if (sync_point) 327 BrowserThread::PostTask(BrowserThread::UI, 328 FROM_HERE, 329 base::Bind(&ReturnVideoFrame, frame, sync_point)); 330 } 331 332 const media::VideoCaptureFormat& 333 VideoCaptureController::GetVideoCaptureFormat() const { 334 DCHECK_CURRENTLY_ON(BrowserThread::IO); 335 return video_capture_format_; 336 } 337 338 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> 339 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( 340 media::VideoFrame::Format format, 341 const gfx::Size& size) { 342 return DoReserveOutputBuffer(format, size); 343 } 344 345 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData( 346 const uint8* data, 347 int length, 348 const VideoCaptureFormat& frame_format, 349 int rotation, 350 base::TimeTicks timestamp) { 351 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData"); 352 353 if (!frame_format.IsValid()) 354 return; 355 356 // Chopped pixels in width/height in case video capture device has odd 357 // numbers for width/height. 358 int chopped_width = 0; 359 int chopped_height = 0; 360 int new_unrotated_width = frame_format.frame_size.width(); 361 int new_unrotated_height = frame_format.frame_size.height(); 362 363 if (new_unrotated_width & 1) { 364 --new_unrotated_width; 365 chopped_width = 1; 366 } 367 if (new_unrotated_height & 1) { 368 --new_unrotated_height; 369 chopped_height = 1; 370 } 371 372 int destination_width = new_unrotated_width; 373 int destination_height = new_unrotated_height; 374 if (rotation == 90 || rotation == 270) { 375 destination_width = new_unrotated_height; 376 destination_height = new_unrotated_width; 377 } 378 const gfx::Size dimensions(destination_width, destination_height); 379 if (!media::VideoFrame::IsValidConfig(media::VideoFrame::I420, 380 dimensions, 381 gfx::Rect(dimensions), 382 dimensions)) { 383 return; 384 } 385 386 scoped_refptr<Buffer> buffer = 387 DoReserveOutputBuffer(media::VideoFrame::I420, dimensions); 388 389 if (!buffer.get()) 390 return; 391 uint8* yplane = NULL; 392 bool flip = false; 393 yplane = reinterpret_cast<uint8*>(buffer->data()); 394 uint8* uplane = 395 yplane + 396 media::VideoFrame::PlaneAllocationSize( 397 media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions); 398 uint8* vplane = 399 uplane + 400 media::VideoFrame::PlaneAllocationSize( 401 media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions); 402 int yplane_stride = dimensions.width(); 403 int uv_plane_stride = yplane_stride / 2; 404 int crop_x = 0; 405 int crop_y = 0; 406 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; 407 408 libyuv::RotationMode rotation_mode = libyuv::kRotate0; 409 if (rotation == 90) 410 rotation_mode = libyuv::kRotate90; 411 else if (rotation == 180) 412 rotation_mode = libyuv::kRotate180; 413 else if (rotation == 270) 414 rotation_mode = libyuv::kRotate270; 415 416 switch (frame_format.pixel_format) { 417 case media::PIXEL_FORMAT_UNKNOWN: // Color format not set. 418 break; 419 case media::PIXEL_FORMAT_I420: 420 DCHECK(!chopped_width && !chopped_height); 421 origin_colorspace = libyuv::FOURCC_I420; 422 break; 423 case media::PIXEL_FORMAT_YV12: 424 DCHECK(!chopped_width && !chopped_height); 425 origin_colorspace = libyuv::FOURCC_YV12; 426 break; 427 case media::PIXEL_FORMAT_NV21: 428 DCHECK(!chopped_width && !chopped_height); 429 origin_colorspace = libyuv::FOURCC_NV21; 430 break; 431 case media::PIXEL_FORMAT_YUY2: 432 DCHECK(!chopped_width && !chopped_height); 433 origin_colorspace = libyuv::FOURCC_YUY2; 434 break; 435 case media::PIXEL_FORMAT_UYVY: 436 DCHECK(!chopped_width && !chopped_height); 437 origin_colorspace = libyuv::FOURCC_UYVY; 438 break; 439 case media::PIXEL_FORMAT_RGB24: 440 origin_colorspace = libyuv::FOURCC_24BG; 441 #if defined(OS_WIN) 442 // TODO(wjia): Currently, for RGB24 on WIN, capture device always 443 // passes in positive src_width and src_height. Remove this hardcoded 444 // value when nagative src_height is supported. The negative src_height 445 // indicates that vertical flipping is needed. 446 flip = true; 447 #endif 448 break; 449 case media::PIXEL_FORMAT_ARGB: 450 origin_colorspace = libyuv::FOURCC_ARGB; 451 break; 452 case media::PIXEL_FORMAT_MJPEG: 453 origin_colorspace = libyuv::FOURCC_MJPG; 454 break; 455 default: 456 NOTREACHED(); 457 } 458 459 libyuv::ConvertToI420(data, 460 length, 461 yplane, 462 yplane_stride, 463 uplane, 464 uv_plane_stride, 465 vplane, 466 uv_plane_stride, 467 crop_x, 468 crop_y, 469 frame_format.frame_size.width(), 470 (flip ? -frame_format.frame_size.height() : 471 frame_format.frame_size.height()), 472 new_unrotated_width, 473 new_unrotated_height, 474 rotation_mode, 475 origin_colorspace); 476 scoped_refptr<media::VideoFrame> frame = 477 media::VideoFrame::WrapExternalPackedMemory( 478 media::VideoFrame::I420, 479 dimensions, 480 gfx::Rect(dimensions), 481 dimensions, 482 yplane, 483 media::VideoFrame::AllocationSize(media::VideoFrame::I420, 484 dimensions), 485 base::SharedMemory::NULLHandle(), 486 base::TimeDelta(), 487 base::Closure()); 488 DCHECK(frame.get()); 489 490 VideoCaptureFormat format( 491 dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420); 492 BrowserThread::PostTask( 493 BrowserThread::IO, 494 FROM_HERE, 495 base::Bind( 496 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, 497 controller_, 498 buffer, 499 format, 500 frame, 501 timestamp)); 502 } 503 504 void 505 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( 506 const scoped_refptr<Buffer>& buffer, 507 const VideoCaptureFormat& buffer_format, 508 const scoped_refptr<media::VideoFrame>& frame, 509 base::TimeTicks timestamp) { 510 BrowserThread::PostTask( 511 BrowserThread::IO, 512 FROM_HERE, 513 base::Bind( 514 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, 515 controller_, 516 buffer, 517 buffer_format, 518 frame, 519 timestamp)); 520 } 521 522 void VideoCaptureController::VideoCaptureDeviceClient::OnError( 523 const std::string& reason) { 524 const std::string log_message = base::StringPrintf( 525 "Error on video capture: %s, OS message: %s", 526 reason.c_str(), 527 logging::SystemErrorCodeToString( 528 logging::GetLastSystemErrorCode()).c_str()); 529 DLOG(ERROR) << log_message; 530 MediaStreamManager::SendMessageToNativeLog(log_message); 531 BrowserThread::PostTask(BrowserThread::IO, 532 FROM_HERE, 533 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); 534 } 535 536 void VideoCaptureController::VideoCaptureDeviceClient::OnLog( 537 const std::string& message) { 538 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message); 539 } 540 541 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> 542 VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer( 543 media::VideoFrame::Format format, 544 const gfx::Size& dimensions) { 545 size_t frame_bytes = 0; 546 if (format == media::VideoFrame::NATIVE_TEXTURE) { 547 DCHECK_EQ(dimensions.width(), 0); 548 DCHECK_EQ(dimensions.height(), 0); 549 } else { 550 // The capture pipeline expects I420 for now. 551 DCHECK_EQ(format, media::VideoFrame::I420) 552 << "Non-I420 output buffer format " << format << " requested"; 553 frame_bytes = media::VideoFrame::AllocationSize(format, dimensions); 554 } 555 556 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; 557 int buffer_id = 558 buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop); 559 if (buffer_id == VideoCaptureBufferPool::kInvalidId) 560 return NULL; 561 void* data; 562 size_t size; 563 buffer_pool_->GetBufferInfo(buffer_id, &data, &size); 564 565 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( 566 new PoolBuffer(buffer_pool_, buffer_id, data, size)); 567 568 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { 569 BrowserThread::PostTask(BrowserThread::IO, 570 FROM_HERE, 571 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, 572 controller_, buffer_id_to_drop)); 573 } 574 575 return output_buffer; 576 } 577 578 VideoCaptureController::~VideoCaptureController() { 579 STLDeleteContainerPointers(controller_clients_.begin(), 580 controller_clients_.end()); 581 UMA_HISTOGRAM_BOOLEAN("Media.VideoCapture.FramesReceived", frame_received_); 582 } 583 584 void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread( 585 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, 586 const media::VideoCaptureFormat& buffer_format, 587 const scoped_refptr<media::VideoFrame>& frame, 588 base::TimeTicks timestamp) { 589 DCHECK_CURRENTLY_ON(BrowserThread::IO); 590 DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId); 591 592 int count = 0; 593 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 594 for (ControllerClients::iterator client_it = controller_clients_.begin(); 595 client_it != controller_clients_.end(); ++client_it) { 596 ControllerClient* client = *client_it; 597 if (client->session_closed || client->paused) 598 continue; 599 600 if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) { 601 client->event_handler->OnMailboxBufferReady(client->controller_id, 602 buffer->id(), 603 *frame->mailbox_holder(), 604 buffer_format, 605 timestamp); 606 } else { 607 bool is_new_buffer = client->known_buffers.insert(buffer->id()).second; 608 if (is_new_buffer) { 609 // On the first use of a buffer on a client, share the memory handle. 610 size_t memory_size = 0; 611 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess( 612 buffer->id(), client->render_process_handle, &memory_size); 613 client->event_handler->OnBufferCreated( 614 client->controller_id, remote_handle, memory_size, buffer->id()); 615 } 616 617 client->event_handler->OnBufferReady( 618 client->controller_id, buffer->id(), buffer_format, 619 frame->visible_rect(), timestamp); 620 } 621 622 bool inserted = 623 client->active_buffers.insert(std::make_pair(buffer->id(), frame)) 624 .second; 625 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id(); 626 count++; 627 } 628 } 629 630 if (!frame_received_) { 631 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width", 632 buffer_format.frame_size.width()); 633 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height", 634 buffer_format.frame_size.height()); 635 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio", 636 buffer_format.frame_size.width(), 637 buffer_format.frame_size.height()); 638 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate", 639 buffer_format.frame_rate); 640 UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.PixelFormat", 641 buffer_format.pixel_format, 642 media::PIXEL_FORMAT_MAX); 643 frame_received_ = true; 644 } 645 646 buffer_pool_->HoldForConsumers(buffer->id(), count); 647 } 648 649 void VideoCaptureController::DoErrorOnIOThread() { 650 DCHECK_CURRENTLY_ON(BrowserThread::IO); 651 state_ = VIDEO_CAPTURE_STATE_ERROR; 652 653 for (ControllerClients::iterator client_it = controller_clients_.begin(); 654 client_it != controller_clients_.end(); ++client_it) { 655 ControllerClient* client = *client_it; 656 if (client->session_closed) 657 continue; 658 659 client->event_handler->OnError(client->controller_id); 660 } 661 } 662 663 void VideoCaptureController::DoBufferDestroyedOnIOThread( 664 int buffer_id_to_drop) { 665 DCHECK_CURRENTLY_ON(BrowserThread::IO); 666 667 for (ControllerClients::iterator client_it = controller_clients_.begin(); 668 client_it != controller_clients_.end(); ++client_it) { 669 ControllerClient* client = *client_it; 670 if (client->session_closed) 671 continue; 672 673 if (client->known_buffers.erase(buffer_id_to_drop)) { 674 client->event_handler->OnBufferDestroyed(client->controller_id, 675 buffer_id_to_drop); 676 } 677 } 678 } 679 680 VideoCaptureController::ControllerClient* 681 VideoCaptureController::FindClient( 682 const VideoCaptureControllerID& id, 683 VideoCaptureControllerEventHandler* handler, 684 const ControllerClients& clients) { 685 for (ControllerClients::const_iterator client_it = clients.begin(); 686 client_it != clients.end(); ++client_it) { 687 if ((*client_it)->controller_id == id && 688 (*client_it)->event_handler == handler) { 689 return *client_it; 690 } 691 } 692 return NULL; 693 } 694 695 VideoCaptureController::ControllerClient* 696 VideoCaptureController::FindClient( 697 int session_id, 698 const ControllerClients& clients) { 699 for (ControllerClients::const_iterator client_it = clients.begin(); 700 client_it != clients.end(); ++client_it) { 701 if ((*client_it)->session_id == session_id) { 702 return *client_it; 703 } 704 } 705 return NULL; 706 } 707 708 int VideoCaptureController::GetClientCount() const { 709 DCHECK_CURRENTLY_ON(BrowserThread::IO); 710 return controller_clients_.size(); 711 } 712 713 int VideoCaptureController::GetActiveClientCount() const { 714 DCHECK_CURRENTLY_ON(BrowserThread::IO); 715 int active_client_count = 0; 716 for (ControllerClient* client : controller_clients_) { 717 if (!client->paused) 718 ++active_client_count; 719 } 720 return active_client_count; 721 } 722 723 } // namespace content 724