| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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. | 2 // found in the LICENSE file. |
| 4 | 3 |
| 5 #include "content/browser/renderer_host/media/video_capture_controller.h" | 4 #include "content/browser/renderer_host/media/video_capture_controller.h" |
| 6 | 5 |
| 7 #include <set> | 6 #include <set> |
| 8 | 7 |
| 9 #include "base/bind.h" | 8 #include "base/bind.h" |
| 10 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 11 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 13 #include "content/browser/renderer_host/media/media_stream_manager.h" | 12 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 14 #include "content/browser/renderer_host/media/video_capture_manager.h" | 13 #include "content/browser/renderer_host/media/video_capture_manager.h" |
| 15 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
| 16 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 17 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
| 18 #include "media/base/yuv_convert.h" | 17 #include "media/base/yuv_convert.h" |
| 19 | 18 |
| 20 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 19 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 21 #include "third_party/libyuv/include/libyuv.h" | 20 #include "third_party/libyuv/include/libyuv.h" |
| 22 #endif | 21 #endif |
| 23 | 22 |
| 24 namespace content { | 23 namespace content { |
| 25 | 24 |
| 25 namespace { |
| 26 |
| 26 // The number of buffers that VideoCaptureBufferPool should allocate. | 27 // The number of buffers that VideoCaptureBufferPool should allocate. |
| 27 static const int kNoOfBuffers = 3; | 28 const int kNoOfBuffers = 3; |
| 29 |
| 30 class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer { |
| 31 public: |
| 32 PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, |
| 33 int buffer_id, |
| 34 void* data, |
| 35 size_t size) |
| 36 : Buffer(data, size), pool_(pool), buffer_id_(buffer_id) {} |
| 37 virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(buffer_id_); } |
| 38 |
| 39 private: |
| 40 const scoped_refptr<VideoCaptureBufferPool> pool_; |
| 41 const int buffer_id_; |
| 42 }; |
| 43 |
| 44 } // anonymous namespace |
| 28 | 45 |
| 29 struct VideoCaptureController::ControllerClient { | 46 struct VideoCaptureController::ControllerClient { |
| 30 ControllerClient( | 47 ControllerClient( |
| 31 const VideoCaptureControllerID& id, | 48 const VideoCaptureControllerID& id, |
| 32 VideoCaptureControllerEventHandler* handler, | 49 VideoCaptureControllerEventHandler* handler, |
| 33 base::ProcessHandle render_process, | 50 base::ProcessHandle render_process, |
| 34 const media::VideoCaptureParams& params) | 51 const media::VideoCaptureParams& params) |
| 35 : controller_id(id), | 52 : controller_id(id), |
| 36 event_handler(handler), | 53 event_handler(handler), |
| 37 render_process_handle(render_process), | 54 render_process_handle(render_process), |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 // v4l2_thread on Linux, and the UI thread for tab capture. | 95 // v4l2_thread on Linux, and the UI thread for tab capture. |
| 79 class VideoCaptureController::VideoCaptureDeviceClient | 96 class VideoCaptureController::VideoCaptureDeviceClient |
| 80 : public media::VideoCaptureDevice::Client { | 97 : public media::VideoCaptureDevice::Client { |
| 81 public: | 98 public: |
| 82 explicit VideoCaptureDeviceClient( | 99 explicit VideoCaptureDeviceClient( |
| 83 const base::WeakPtr<VideoCaptureController>& controller, | 100 const base::WeakPtr<VideoCaptureController>& controller, |
| 84 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); | 101 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); |
| 85 virtual ~VideoCaptureDeviceClient(); | 102 virtual ~VideoCaptureDeviceClient(); |
| 86 | 103 |
| 87 // VideoCaptureDevice::Client implementation. | 104 // VideoCaptureDevice::Client implementation. |
| 88 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer( | 105 virtual scoped_ptr<Buffer> ReserveOutputBuffer( |
| 106 media::VideoFrame::Format format, |
| 89 const gfx::Size& size) OVERRIDE; | 107 const gfx::Size& size) OVERRIDE; |
| 90 virtual void OnIncomingCapturedFrame(const uint8* data, | 108 virtual void OnIncomingCapturedFrame(const uint8* data, |
| 91 int length, | 109 int length, |
| 92 base::Time timestamp, | 110 base::Time timestamp, |
| 93 int rotation, | 111 int rotation, |
| 94 bool flip_vert, | 112 bool flip_vert, |
| 95 bool flip_horiz) OVERRIDE; | 113 bool flip_horiz) OVERRIDE; |
| 96 virtual void OnIncomingCapturedVideoFrame( | 114 virtual void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer, |
| 97 const scoped_refptr<media::VideoFrame>& frame, | 115 media::VideoFrame::Format format, |
| 98 base::Time timestamp) OVERRIDE; | 116 const gfx::Size& dimensions, |
| 117 base::Time timestamp) OVERRIDE; |
| 99 virtual void OnError() OVERRIDE; | 118 virtual void OnError() OVERRIDE; |
| 100 virtual void OnFrameInfo( | 119 virtual void OnFrameInfo( |
| 101 const media::VideoCaptureCapability& info) OVERRIDE; | 120 const media::VideoCaptureCapability& info) OVERRIDE; |
| 102 virtual void OnFrameInfoChanged( | 121 virtual void OnFrameInfoChanged( |
| 103 const media::VideoCaptureCapability& info) OVERRIDE; | 122 const media::VideoCaptureCapability& info) OVERRIDE; |
| 104 | 123 |
| 105 private: | 124 private: |
| 106 scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame( | 125 scoped_ptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format, |
| 107 const gfx::Size& size, | 126 const gfx::Size& dimensions, |
| 108 int rotation); | 127 int rotation); |
| 109 | 128 |
| 110 // The controller to which we post events. | 129 // The controller to which we post events. |
| 111 const base::WeakPtr<VideoCaptureController> controller_; | 130 const base::WeakPtr<VideoCaptureController> controller_; |
| 112 | 131 |
| 113 // The pool of shared-memory buffers used for capturing. | 132 // The pool of shared-memory buffers used for capturing. |
| 114 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; | 133 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; |
| 115 | 134 |
| 135 // The set of buffers that have been used for rotated capturing. |
| 136 std::set<int> rotated_buffers_; |
| 137 |
| 116 // Chopped pixels in width/height in case video capture device has odd | 138 // Chopped pixels in width/height in case video capture device has odd |
| 117 // numbers for width/height. | 139 // numbers for width/height. |
| 118 int chopped_width_; | 140 int chopped_width_; |
| 119 int chopped_height_; | 141 int chopped_height_; |
| 120 | 142 |
| 121 // Tracks the current frame format. | 143 // Tracks the current frame format. |
| 122 media::VideoCaptureCapability frame_info_; | 144 media::VideoCaptureCapability frame_info_; |
| 123 }; | 145 }; |
| 124 | 146 |
| 125 VideoCaptureController::VideoCaptureController() | 147 VideoCaptureController::VideoCaptureController() |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 // If this buffer is not held by this client, or this client doesn't exist | 253 // If this buffer is not held by this client, or this client doesn't exist |
| 232 // in controller, do nothing. | 254 // in controller, do nothing. |
| 233 if (!client || !client->active_buffers.erase(buffer_id)) { | 255 if (!client || !client->active_buffers.erase(buffer_id)) { |
| 234 NOTREACHED(); | 256 NOTREACHED(); |
| 235 return; | 257 return; |
| 236 } | 258 } |
| 237 | 259 |
| 238 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 260 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
| 239 } | 261 } |
| 240 | 262 |
| 241 scoped_refptr<media::VideoFrame> | 263 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> |
| 242 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( | 264 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( |
| 265 media::VideoFrame::Format format, |
| 243 const gfx::Size& size) { | 266 const gfx::Size& size) { |
| 244 return DoReserveI420VideoFrame(size, 0); | 267 return DoReserveOutputBuffer(format, size, 0); |
| 245 } | 268 } |
| 246 | 269 |
| 247 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | 270 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( |
| 248 const uint8* data, | 271 const uint8* data, |
| 249 int length, | 272 int length, |
| 250 base::Time timestamp, | 273 base::Time timestamp, |
| 251 int rotation, | 274 int rotation, |
| 252 bool flip_vert, | 275 bool flip_vert, |
| 253 bool flip_horiz) { | 276 bool flip_horiz) { |
| 254 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 277 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
| 255 | 278 |
| 256 if (!frame_info_.IsValid()) | 279 if (!frame_info_.IsValid()) |
| 257 return; | 280 return; |
| 258 | 281 |
| 259 scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame( | 282 const gfx::Size dimensions(frame_info_.width, frame_info_.height); |
| 260 gfx::Size(frame_info_.width, frame_info_.height), rotation); | 283 scoped_ptr<Buffer> buffer = |
| 284 DoReserveOutputBuffer(media::VideoFrame::I420, dimensions, rotation); |
| 261 | 285 |
| 262 if (!dst.get()) | 286 if (!buffer) |
| 263 return; | 287 return; |
| 264 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 288 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 265 | 289 uint8* yplane = reinterpret_cast<uint8*>(buffer->data()); |
| 266 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 290 uint8* uplane = |
| 267 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 291 yplane + |
| 268 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 292 media::VideoFrame::PlaneAllocationSize( |
| 293 media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions); |
| 294 uint8* vplane = |
| 295 uplane + |
| 296 media::VideoFrame::PlaneAllocationSize( |
| 297 media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions); |
| 269 int yplane_stride = frame_info_.width; | 298 int yplane_stride = frame_info_.width; |
| 270 int uv_plane_stride = (frame_info_.width + 1) / 2; | 299 int uv_plane_stride = (frame_info_.width + 1) / 2; |
| 271 int crop_x = 0; | 300 int crop_x = 0; |
| 272 int crop_y = 0; | 301 int crop_y = 0; |
| 273 int destination_width = frame_info_.width; | 302 int destination_width = frame_info_.width; |
| 274 int destination_height = frame_info_.height; | 303 int destination_height = frame_info_.height; |
| 275 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; | 304 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; |
| 276 // Assuming rotation happens first and flips next, we can consolidate both | 305 // Assuming rotation happens first and flips next, we can consolidate both |
| 277 // vertical and horizontal flips together with rotation into two variables: | 306 // vertical and horizontal flips together with rotation into two variables: |
| 278 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 | 307 // new_rotation = (rotation + 180 * vertical_flip) modulo 360 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 } | 410 } |
| 382 #else | 411 #else |
| 383 // Libyuv is not linked in for Android WebView builds, but video capture is | 412 // Libyuv is not linked in for Android WebView builds, but video capture is |
| 384 // not used in those builds either. Whenever libyuv is added in that build, | 413 // not used in those builds either. Whenever libyuv is added in that build, |
| 385 // address all these #ifdef parts, see http://crbug.com/299611 . | 414 // address all these #ifdef parts, see http://crbug.com/299611 . |
| 386 NOTREACHED(); | 415 NOTREACHED(); |
| 387 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 416 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 388 BrowserThread::PostTask( | 417 BrowserThread::PostTask( |
| 389 BrowserThread::IO, | 418 BrowserThread::IO, |
| 390 FROM_HERE, | 419 FROM_HERE, |
| 391 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 420 base::Bind( |
| 392 controller_, | 421 &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread, |
| 393 dst, | 422 controller_, |
| 394 frame_info_.frame_rate, | 423 base::Passed(&buffer), |
| 395 timestamp)); | 424 dimensions, |
| 425 frame_info_.frame_rate, |
| 426 timestamp)); |
| 396 } | 427 } |
| 397 | 428 |
| 398 void | 429 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedBuffer( |
| 399 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 430 scoped_ptr<Buffer> buffer, |
| 400 const scoped_refptr<media::VideoFrame>& frame, | 431 media::VideoFrame::Format format, |
| 432 const gfx::Size& dimensions, |
| 401 base::Time timestamp) { | 433 base::Time timestamp) { |
| 434 // The capture pipeline expects I420 for now. |
| 435 DCHECK_EQ(format, media::VideoFrame::I420) |
| 436 << "Non-I420 output buffer returned"; |
| 437 DCHECK_NE(buffer_pool_->RecognizeReservedBuffer(buffer->data()), |
| 438 VideoCaptureBufferPool::kInvalidId) |
| 439 << "Non-reserved buffer returned"; |
| 402 | 440 |
| 403 // If this is a frame that belongs to the buffer pool, we can forward it | 441 BrowserThread::PostTask( |
| 404 // directly to the IO thread and be done. | 442 BrowserThread::IO, |
| 405 if (buffer_pool_->RecognizeReservedBuffer( | 443 FROM_HERE, |
| 406 frame->shared_memory_handle()) >= 0) { | 444 base::Bind( |
| 407 BrowserThread::PostTask(BrowserThread::IO, | 445 &VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread, |
| 408 FROM_HERE, | 446 controller_, |
| 409 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 447 base::Passed(&buffer), |
| 410 controller_, frame, frame_info_.frame_rate, timestamp)); | 448 dimensions, |
| 411 return; | 449 frame_info_.frame_rate, |
| 412 } | 450 timestamp)); |
| 413 | |
| 414 NOTREACHED() << "Frames should always belong to the buffer pool."; | |
| 415 } | 451 } |
| 416 | 452 |
| 417 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { | 453 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { |
| 418 BrowserThread::PostTask(BrowserThread::IO, | 454 BrowserThread::PostTask(BrowserThread::IO, |
| 419 FROM_HERE, | 455 FROM_HERE, |
| 420 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); | 456 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); |
| 421 } | 457 } |
| 422 | 458 |
| 423 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( | 459 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( |
| 424 const media::VideoCaptureCapability& info) { | 460 const media::VideoCaptureCapability& info) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 436 } else { | 472 } else { |
| 437 chopped_height_ = 0; | 473 chopped_height_ = 0; |
| 438 } | 474 } |
| 439 } | 475 } |
| 440 | 476 |
| 441 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( | 477 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( |
| 442 const media::VideoCaptureCapability& info) { | 478 const media::VideoCaptureCapability& info) { |
| 443 OnFrameInfo(info); | 479 OnFrameInfo(info); |
| 444 } | 480 } |
| 445 | 481 |
| 446 scoped_refptr<media::VideoFrame> | 482 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> |
| 447 VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame( | 483 VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer( |
| 448 const gfx::Size& size, | 484 media::VideoFrame::Format format, |
| 485 const gfx::Size& dimensions, |
| 449 int rotation) { | 486 int rotation) { |
| 487 // The capture pipeline expects I420 for now. |
| 488 DCHECK_EQ(format, media::VideoFrame::I420) |
| 489 << "Non-I420 output buffer requested"; |
| 490 |
| 450 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; | 491 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; |
| 451 scoped_refptr<media::VideoFrame> frame = | 492 const size_t frame_bytes = |
| 452 buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop); | 493 media::VideoFrame::AllocationSize(format, dimensions); |
| 494 |
| 495 int buffer_id = |
| 496 buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop); |
| 497 if (buffer_id == VideoCaptureBufferPool::kInvalidId) |
| 498 return scoped_ptr<Buffer>(); |
| 499 void* data; |
| 500 size_t size; |
| 501 buffer_pool_->GetBufferInfo(buffer_id, &data, &size); |
| 502 |
| 503 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( |
| 504 new PoolBuffer(buffer_pool_, buffer_id, data, size)); |
| 505 buffer_id = VideoCaptureBufferPool::kInvalidId; |
| 506 |
| 453 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { | 507 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { |
| 454 BrowserThread::PostTask(BrowserThread::IO, | 508 BrowserThread::PostTask(BrowserThread::IO, |
| 455 FROM_HERE, | 509 FROM_HERE, |
| 456 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, | 510 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, |
| 457 controller_, buffer_id_to_drop)); | 511 controller_, buffer_id_to_drop)); |
| 512 rotated_buffers_.erase(buffer_id_to_drop); |
| 458 } | 513 } |
| 459 return frame; | 514 |
| 515 // If rotation is required, and the returned frame has not been rotated, |
| 516 // perform a clear to clear the letterbox borders. |
| 517 if ((rotation % 180) == 0) { |
| 518 rotated_buffers_.erase(buffer_id); |
| 519 } else { |
| 520 if (!rotated_buffers_.count(buffer_id)) { |
| 521 // TODO(jiayl): Generalize the |rotation| mechanism. |
| 522 memset(output_buffer->data(), 0, output_buffer->size()); |
| 523 rotated_buffers_.insert(buffer_id); |
| 524 } |
| 525 } |
| 526 |
| 527 return output_buffer.Pass(); |
| 460 } | 528 } |
| 461 | 529 |
| 462 VideoCaptureController::~VideoCaptureController() { | 530 VideoCaptureController::~VideoCaptureController() { |
| 463 STLDeleteContainerPointers(controller_clients_.begin(), | 531 STLDeleteContainerPointers(controller_clients_.begin(), |
| 464 controller_clients_.end()); | 532 controller_clients_.end()); |
| 465 } | 533 } |
| 466 | 534 |
| 467 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 535 void VideoCaptureController::DoIncomingCapturedI420BufferOnIOThread( |
| 468 const scoped_refptr<media::VideoFrame>& reserved_frame, | 536 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, |
| 537 const gfx::Size& dimensions, |
| 469 int frame_rate, | 538 int frame_rate, |
| 470 base::Time timestamp) { | 539 base::Time timestamp) { |
| 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 472 | 541 |
| 473 int buffer_id = buffer_pool_->RecognizeReservedBuffer( | 542 int buffer_id = buffer_pool_->RecognizeReservedBuffer(buffer->data()); |
| 474 reserved_frame->shared_memory_handle()); | |
| 475 if (buffer_id < 0) { | 543 if (buffer_id < 0) { |
| 476 NOTREACHED(); | 544 NOTREACHED(); |
| 477 return; | 545 return; |
| 478 } | 546 } |
| 479 | 547 |
| 548 // |buffer_id| will remain valid as long as |buffer| remains valid, so |
| 549 // it will be valid for the remainder of this function. |
| 550 |
| 480 media::VideoCaptureFormat frame_format( | 551 media::VideoCaptureFormat frame_format( |
| 481 reserved_frame->coded_size().width(), | 552 dimensions.width(), |
| 482 reserved_frame->coded_size().height(), | 553 dimensions.height(), |
| 483 frame_rate, | 554 frame_rate, |
| 484 media::VariableResolutionVideoCaptureDevice); | 555 media::VariableResolutionVideoCaptureDevice); |
| 485 | 556 |
| 486 int count = 0; | 557 int count = 0; |
| 487 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 558 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 488 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 559 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 489 client_it != controller_clients_.end(); ++client_it) { | 560 client_it != controller_clients_.end(); ++client_it) { |
| 490 ControllerClient* client = *client_it; | 561 ControllerClient* client = *client_it; |
| 491 if (client->session_closed) | 562 if (client->session_closed) |
| 492 continue; | 563 continue; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 } | 644 } |
| 574 return NULL; | 645 return NULL; |
| 575 } | 646 } |
| 576 | 647 |
| 577 int VideoCaptureController::GetClientCount() { | 648 int VideoCaptureController::GetClientCount() { |
| 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 579 return controller_clients_.size(); | 650 return controller_clients_.size(); |
| 580 } | 651 } |
| 581 | 652 |
| 582 } // namespace content | 653 } // namespace content |
| OLD | NEW |