[blink-in-js] Migrate resources required for blink-in-js to grd - part 2
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_controller.cc
blob4b6d4b94b1e0fca3c3d4827a4c0bb200130f42ea
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.
5 #include "content/browser/renderer_host/media/video_capture_controller.h"
7 #include <map>
8 #include <set>
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"
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
32 using media::VideoCaptureFormat;
34 namespace content {
36 namespace {
38 static const int kInfiniteRatio = 99999;
40 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
41 UMA_HISTOGRAM_SPARSE_SLOWLY( \
42 name, \
43 (height) ? ((width) * 100) / (height) : kInfiniteRatio);
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());
55 private:
56 virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); }
58 const scoped_refptr<VideoCaptureBufferPool> pool_;
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();
68 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
69 gl_helper_->WaitSyncPoint(sync_point);
72 private:
73 GLHelper* gl_helper_;
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);
93 } // anonymous namespace
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) {}
108 ~ControllerClient() {}
110 // ID used for identifying this object.
111 const VideoCaptureControllerID controller_id;
112 VideoCaptureControllerEventHandler* const event_handler;
114 // Handle to the render process that will receive the capture buffers.
115 const base::ProcessHandle render_process_handle;
116 const media::VideoCaptureSessionId session_id;
117 const media::VideoCaptureParams parameters;
119 // Buffers that are currently known to this client.
120 std::set<int> known_buffers;
122 // Buffers currently held by this client, and syncpoint callback to call when
123 // they are returned from the client.
124 typedef std::map<int, scoped_refptr<media::VideoFrame> > ActiveBufferMap;
125 ActiveBufferMap active_buffers;
127 // State of capture session, controlled by VideoCaptureManager directly. This
128 // transitions to true as soon as StopSession() occurs, at which point the
129 // client is sent an OnEnded() event. However, because the client retains a
130 // VideoCaptureController* pointer, its ControllerClient entry lives on until
131 // it unregisters itself via RemoveClient(), which may happen asynchronously.
133 // TODO(nick): If we changed the semantics of VideoCaptureHost so that
134 // OnEnded() events were processed synchronously (with the RemoveClient() done
135 // implicitly), we could avoid tracking this state here in the Controller, and
136 // simplify the code in both places.
137 bool session_closed;
140 // Receives events from the VideoCaptureDevice and posts them to a
141 // VideoCaptureController on the IO thread. An instance of this class may safely
142 // outlive its target VideoCaptureController.
144 // Methods of this class may be called from any thread, and in practice will
145 // often be called on some auxiliary thread depending on the platform and the
146 // device type; including, for example, the DirectShow thread on Windows, the
147 // v4l2_thread on Linux, and the UI thread for tab capture.
148 class VideoCaptureController::VideoCaptureDeviceClient
149 : public media::VideoCaptureDevice::Client {
150 public:
151 explicit VideoCaptureDeviceClient(
152 const base::WeakPtr<VideoCaptureController>& controller,
153 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
154 virtual ~VideoCaptureDeviceClient();
156 // VideoCaptureDevice::Client implementation.
157 virtual scoped_refptr<Buffer> ReserveOutputBuffer(
158 media::VideoFrame::Format format,
159 const gfx::Size& size) OVERRIDE;
160 virtual void OnIncomingCapturedData(const uint8* data,
161 int length,
162 const VideoCaptureFormat& frame_format,
163 int rotation,
164 base::TimeTicks timestamp) OVERRIDE;
165 virtual void OnIncomingCapturedVideoFrame(
166 const scoped_refptr<Buffer>& buffer,
167 const VideoCaptureFormat& buffer_format,
168 const scoped_refptr<media::VideoFrame>& frame,
169 base::TimeTicks timestamp) OVERRIDE;
170 virtual void OnError(const std::string& reason) OVERRIDE;
171 virtual void OnLog(const std::string& message) OVERRIDE;
173 private:
174 scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
175 const gfx::Size& dimensions);
177 // The controller to which we post events.
178 const base::WeakPtr<VideoCaptureController> controller_;
180 // The pool of shared-memory buffers used for capturing.
181 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
184 VideoCaptureController::VideoCaptureController(int max_buffers)
185 : buffer_pool_(new VideoCaptureBufferPool(max_buffers)),
186 state_(VIDEO_CAPTURE_STATE_STARTED),
187 frame_received_(false),
188 weak_ptr_factory_(this) {
191 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
192 const base::WeakPtr<VideoCaptureController>& controller,
193 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
194 : controller_(controller), buffer_pool_(buffer_pool) {}
196 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
198 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() {
199 return weak_ptr_factory_.GetWeakPtr();
202 scoped_ptr<media::VideoCaptureDevice::Client>
203 VideoCaptureController::NewDeviceClient() {
204 scoped_ptr<media::VideoCaptureDevice::Client> result(
205 new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_));
206 return result.Pass();
209 void VideoCaptureController::AddClient(
210 const VideoCaptureControllerID& id,
211 VideoCaptureControllerEventHandler* event_handler,
212 base::ProcessHandle render_process,
213 media::VideoCaptureSessionId session_id,
214 const media::VideoCaptureParams& params) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id
217 << ", " << params.requested_format.frame_size.ToString()
218 << ", " << params.requested_format.frame_rate
219 << ", " << session_id
220 << ")";
222 // If this is the first client added to the controller, cache the parameters.
223 if (!controller_clients_.size())
224 video_capture_format_ = params.requested_format;
226 // Signal error in case device is already in error state.
227 if (state_ == VIDEO_CAPTURE_STATE_ERROR) {
228 event_handler->OnError(id);
229 return;
232 // Do nothing if this client has called AddClient before.
233 if (FindClient(id, event_handler, controller_clients_))
234 return;
236 ControllerClient* client = new ControllerClient(
237 id, event_handler, render_process, session_id, params);
238 // If we already have gotten frame_info from the device, repeat it to the new
239 // client.
240 if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
241 controller_clients_.push_back(client);
242 return;
246 int VideoCaptureController::RemoveClient(
247 const VideoCaptureControllerID& id,
248 VideoCaptureControllerEventHandler* event_handler) {
249 DCHECK_CURRENTLY_ON(BrowserThread::IO);
250 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id;
252 ControllerClient* client = FindClient(id, event_handler, controller_clients_);
253 if (!client)
254 return kInvalidMediaCaptureSessionId;
256 // Take back all buffers held by the |client|.
257 for (ControllerClient::ActiveBufferMap::iterator buffer_it =
258 client->active_buffers.begin();
259 buffer_it != client->active_buffers.end();
260 ++buffer_it) {
261 buffer_pool_->RelinquishConsumerHold(buffer_it->first, 1);
263 client->active_buffers.clear();
265 int session_id = client->session_id;
266 controller_clients_.remove(client);
267 delete client;
269 return session_id;
272 void VideoCaptureController::StopSession(int session_id) {
273 DCHECK_CURRENTLY_ON(BrowserThread::IO);
274 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
276 ControllerClient* client = FindClient(session_id, controller_clients_);
278 if (client) {
279 client->session_closed = true;
280 client->event_handler->OnEnded(client->controller_id);
284 void VideoCaptureController::ReturnBuffer(
285 const VideoCaptureControllerID& id,
286 VideoCaptureControllerEventHandler* event_handler,
287 int buffer_id,
288 uint32 sync_point) {
289 DCHECK_CURRENTLY_ON(BrowserThread::IO);
291 ControllerClient* client = FindClient(id, event_handler, controller_clients_);
293 // If this buffer is not held by this client, or this client doesn't exist
294 // in controller, do nothing.
295 ControllerClient::ActiveBufferMap::iterator iter;
296 if (!client || (iter = client->active_buffers.find(buffer_id)) ==
297 client->active_buffers.end()) {
298 NOTREACHED();
299 return;
301 scoped_refptr<media::VideoFrame> frame = iter->second;
302 client->active_buffers.erase(iter);
303 buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
305 if (sync_point)
306 BrowserThread::PostTask(BrowserThread::UI,
307 FROM_HERE,
308 base::Bind(&ReturnVideoFrame, frame, sync_point));
311 const media::VideoCaptureFormat&
312 VideoCaptureController::GetVideoCaptureFormat() const {
313 DCHECK_CURRENTLY_ON(BrowserThread::IO);
314 return video_capture_format_;
317 scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
318 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
319 media::VideoFrame::Format format,
320 const gfx::Size& size) {
321 return DoReserveOutputBuffer(format, size);
324 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
325 const uint8* data,
326 int length,
327 const VideoCaptureFormat& frame_format,
328 int rotation,
329 base::TimeTicks timestamp) {
330 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData");
332 if (!frame_format.IsValid())
333 return;
335 // Chopped pixels in width/height in case video capture device has odd
336 // numbers for width/height.
337 int chopped_width = 0;
338 int chopped_height = 0;
339 int new_unrotated_width = frame_format.frame_size.width();
340 int new_unrotated_height = frame_format.frame_size.height();
342 if (new_unrotated_width & 1) {
343 --new_unrotated_width;
344 chopped_width = 1;
346 if (new_unrotated_height & 1) {
347 --new_unrotated_height;
348 chopped_height = 1;
351 int destination_width = new_unrotated_width;
352 int destination_height = new_unrotated_height;
353 if (rotation == 90 || rotation == 270) {
354 destination_width = new_unrotated_height;
355 destination_height = new_unrotated_width;
357 const gfx::Size dimensions(destination_width, destination_height);
358 if (!media::VideoFrame::IsValidConfig(media::VideoFrame::I420,
359 dimensions,
360 gfx::Rect(dimensions),
361 dimensions)) {
362 return;
365 scoped_refptr<Buffer> buffer =
366 DoReserveOutputBuffer(media::VideoFrame::I420, dimensions);
368 if (!buffer.get())
369 return;
370 uint8* yplane = NULL;
371 bool flip = false;
372 yplane = reinterpret_cast<uint8*>(buffer->data());
373 uint8* uplane =
374 yplane +
375 media::VideoFrame::PlaneAllocationSize(
376 media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions);
377 uint8* vplane =
378 uplane +
379 media::VideoFrame::PlaneAllocationSize(
380 media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions);
381 int yplane_stride = dimensions.width();
382 int uv_plane_stride = yplane_stride / 2;
383 int crop_x = 0;
384 int crop_y = 0;
385 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
387 libyuv::RotationMode rotation_mode = libyuv::kRotate0;
388 if (rotation == 90)
389 rotation_mode = libyuv::kRotate90;
390 else if (rotation == 180)
391 rotation_mode = libyuv::kRotate180;
392 else if (rotation == 270)
393 rotation_mode = libyuv::kRotate270;
395 switch (frame_format.pixel_format) {
396 case media::PIXEL_FORMAT_UNKNOWN: // Color format not set.
397 break;
398 case media::PIXEL_FORMAT_I420:
399 DCHECK(!chopped_width && !chopped_height);
400 origin_colorspace = libyuv::FOURCC_I420;
401 break;
402 case media::PIXEL_FORMAT_YV12:
403 DCHECK(!chopped_width && !chopped_height);
404 origin_colorspace = libyuv::FOURCC_YV12;
405 break;
406 case media::PIXEL_FORMAT_NV21:
407 DCHECK(!chopped_width && !chopped_height);
408 origin_colorspace = libyuv::FOURCC_NV21;
409 break;
410 case media::PIXEL_FORMAT_YUY2:
411 DCHECK(!chopped_width && !chopped_height);
412 origin_colorspace = libyuv::FOURCC_YUY2;
413 break;
414 case media::PIXEL_FORMAT_UYVY:
415 DCHECK(!chopped_width && !chopped_height);
416 origin_colorspace = libyuv::FOURCC_UYVY;
417 break;
418 case media::PIXEL_FORMAT_RGB24:
419 origin_colorspace = libyuv::FOURCC_24BG;
420 #if defined(OS_WIN)
421 // TODO(wjia): Currently, for RGB24 on WIN, capture device always
422 // passes in positive src_width and src_height. Remove this hardcoded
423 // value when nagative src_height is supported. The negative src_height
424 // indicates that vertical flipping is needed.
425 flip = true;
426 #endif
427 break;
428 case media::PIXEL_FORMAT_ARGB:
429 origin_colorspace = libyuv::FOURCC_ARGB;
430 break;
431 case media::PIXEL_FORMAT_MJPEG:
432 origin_colorspace = libyuv::FOURCC_MJPG;
433 break;
434 default:
435 NOTREACHED();
438 libyuv::ConvertToI420(data,
439 length,
440 yplane,
441 yplane_stride,
442 uplane,
443 uv_plane_stride,
444 vplane,
445 uv_plane_stride,
446 crop_x,
447 crop_y,
448 frame_format.frame_size.width(),
449 (flip ? -frame_format.frame_size.height() :
450 frame_format.frame_size.height()),
451 new_unrotated_width,
452 new_unrotated_height,
453 rotation_mode,
454 origin_colorspace);
455 scoped_refptr<media::VideoFrame> frame =
456 media::VideoFrame::WrapExternalPackedMemory(
457 media::VideoFrame::I420,
458 dimensions,
459 gfx::Rect(dimensions),
460 dimensions,
461 yplane,
462 media::VideoFrame::AllocationSize(media::VideoFrame::I420,
463 dimensions),
464 base::SharedMemory::NULLHandle(),
465 base::TimeDelta(),
466 base::Closure());
467 DCHECK(frame.get());
469 VideoCaptureFormat format(
470 dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420);
471 BrowserThread::PostTask(
472 BrowserThread::IO,
473 FROM_HERE,
474 base::Bind(
475 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
476 controller_,
477 buffer,
478 format,
479 frame,
480 timestamp));
483 void
484 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
485 const scoped_refptr<Buffer>& buffer,
486 const VideoCaptureFormat& buffer_format,
487 const scoped_refptr<media::VideoFrame>& frame,
488 base::TimeTicks timestamp) {
489 BrowserThread::PostTask(
490 BrowserThread::IO,
491 FROM_HERE,
492 base::Bind(
493 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
494 controller_,
495 buffer,
496 buffer_format,
497 frame,
498 timestamp));
501 void VideoCaptureController::VideoCaptureDeviceClient::OnError(
502 const std::string& reason) {
503 const std::string log_message = base::StringPrintf(
504 "Error on video capture: %s, OS message: %s",
505 reason.c_str(),
506 logging::SystemErrorCodeToString(
507 logging::GetLastSystemErrorCode()).c_str());
508 DLOG(ERROR) << log_message;
509 MediaStreamManager::SendMessageToNativeLog(log_message);
510 BrowserThread::PostTask(BrowserThread::IO,
511 FROM_HERE,
512 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
515 void VideoCaptureController::VideoCaptureDeviceClient::OnLog(
516 const std::string& message) {
517 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
520 scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
521 VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
522 media::VideoFrame::Format format,
523 const gfx::Size& dimensions) {
524 size_t frame_bytes = 0;
525 if (format == media::VideoFrame::NATIVE_TEXTURE) {
526 DCHECK_EQ(dimensions.width(), 0);
527 DCHECK_EQ(dimensions.height(), 0);
528 } else {
529 // The capture pipeline expects I420 for now.
530 DCHECK_EQ(format, media::VideoFrame::I420)
531 << "Non-I420 output buffer format " << format << " requested";
532 frame_bytes = media::VideoFrame::AllocationSize(format, dimensions);
535 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
536 int buffer_id =
537 buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
538 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
539 return NULL;
540 void* data;
541 size_t size;
542 buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
544 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
545 new PoolBuffer(buffer_pool_, buffer_id, data, size));
547 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
548 BrowserThread::PostTask(BrowserThread::IO,
549 FROM_HERE,
550 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
551 controller_, buffer_id_to_drop));
554 return output_buffer;
557 VideoCaptureController::~VideoCaptureController() {
558 STLDeleteContainerPointers(controller_clients_.begin(),
559 controller_clients_.end());
560 UMA_HISTOGRAM_BOOLEAN("Media.VideoCapture.FramesReceived", frame_received_);
563 void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
564 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
565 const media::VideoCaptureFormat& buffer_format,
566 const scoped_refptr<media::VideoFrame>& frame,
567 base::TimeTicks timestamp) {
568 DCHECK_CURRENTLY_ON(BrowserThread::IO);
569 DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId);
571 int count = 0;
572 if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
573 for (ControllerClients::iterator client_it = controller_clients_.begin();
574 client_it != controller_clients_.end(); ++client_it) {
575 ControllerClient* client = *client_it;
576 if (client->session_closed)
577 continue;
579 if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
580 client->event_handler->OnMailboxBufferReady(client->controller_id,
581 buffer->id(),
582 *frame->mailbox_holder(),
583 buffer_format,
584 timestamp);
585 } else {
586 bool is_new_buffer = client->known_buffers.insert(buffer->id()).second;
587 if (is_new_buffer) {
588 // On the first use of a buffer on a client, share the memory handle.
589 size_t memory_size = 0;
590 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
591 buffer->id(), client->render_process_handle, &memory_size);
592 client->event_handler->OnBufferCreated(
593 client->controller_id, remote_handle, memory_size, buffer->id());
596 client->event_handler->OnBufferReady(
597 client->controller_id, buffer->id(), buffer_format,
598 frame->visible_rect(), timestamp);
601 bool inserted =
602 client->active_buffers.insert(std::make_pair(buffer->id(), frame))
603 .second;
604 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id();
605 count++;
609 if (!frame_received_) {
610 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
611 buffer_format.frame_size.width());
612 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
613 buffer_format.frame_size.height());
614 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
615 buffer_format.frame_size.width(),
616 buffer_format.frame_size.height());
617 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate",
618 buffer_format.frame_rate);
619 UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.PixelFormat",
620 buffer_format.pixel_format,
621 media::PIXEL_FORMAT_MAX);
622 frame_received_ = true;
625 buffer_pool_->HoldForConsumers(buffer->id(), count);
628 void VideoCaptureController::DoErrorOnIOThread() {
629 DCHECK_CURRENTLY_ON(BrowserThread::IO);
630 state_ = VIDEO_CAPTURE_STATE_ERROR;
632 for (ControllerClients::iterator client_it = controller_clients_.begin();
633 client_it != controller_clients_.end(); ++client_it) {
634 ControllerClient* client = *client_it;
635 if (client->session_closed)
636 continue;
638 client->event_handler->OnError(client->controller_id);
642 void VideoCaptureController::DoBufferDestroyedOnIOThread(
643 int buffer_id_to_drop) {
644 DCHECK_CURRENTLY_ON(BrowserThread::IO);
646 for (ControllerClients::iterator client_it = controller_clients_.begin();
647 client_it != controller_clients_.end(); ++client_it) {
648 ControllerClient* client = *client_it;
649 if (client->session_closed)
650 continue;
652 if (client->known_buffers.erase(buffer_id_to_drop)) {
653 client->event_handler->OnBufferDestroyed(client->controller_id,
654 buffer_id_to_drop);
659 VideoCaptureController::ControllerClient*
660 VideoCaptureController::FindClient(
661 const VideoCaptureControllerID& id,
662 VideoCaptureControllerEventHandler* handler,
663 const ControllerClients& clients) {
664 for (ControllerClients::const_iterator client_it = clients.begin();
665 client_it != clients.end(); ++client_it) {
666 if ((*client_it)->controller_id == id &&
667 (*client_it)->event_handler == handler) {
668 return *client_it;
671 return NULL;
674 VideoCaptureController::ControllerClient*
675 VideoCaptureController::FindClient(
676 int session_id,
677 const ControllerClients& clients) {
678 for (ControllerClients::const_iterator client_it = clients.begin();
679 client_it != clients.end(); ++client_it) {
680 if ((*client_it)->session_id == session_id) {
681 return *client_it;
684 return NULL;
687 int VideoCaptureController::GetClientCount() {
688 DCHECK_CURRENTLY_ON(BrowserThread::IO);
689 return controller_clients_.size();
692 } // namespace content