Add PIXEL_FORMAT_NV12 into VideoPixelFormat
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_controller.cc
blobf05d93fc265be8f968b49fa14ae121ebae66111a
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/compositor/image_transport_factory.h"
28 #endif
30 using media::VideoCaptureFormat;
32 namespace content {
34 namespace {
36 static const int kInfiniteRatio = 99999;
38 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
39 UMA_HISTOGRAM_SPARSE_SLOWLY( \
40 name, \
41 (height) ? ((width) * 100) / (height) : kInfiniteRatio);
43 class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
44 public:
45 PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
46 int buffer_id,
47 void* data,
48 size_t size)
49 : Buffer(buffer_id, data, size), pool_(pool) {
50 DCHECK(pool_.get());
53 private:
54 ~PoolBuffer() override { pool_->RelinquishProducerReservation(id()); }
56 const scoped_refptr<VideoCaptureBufferPool> pool_;
59 class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
60 public:
61 explicit SyncPointClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {}
62 ~SyncPointClientImpl() override {}
63 uint32 InsertSyncPoint() override { return gl_helper_->InsertSyncPoint(); }
64 void WaitSyncPoint(uint32 sync_point) override {
65 gl_helper_->WaitSyncPoint(sync_point);
68 private:
69 GLHelper* gl_helper_;
72 void ReturnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
73 uint32 sync_point) {
74 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 #if defined(OS_ANDROID)
76 NOTREACHED();
77 #else
78 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
79 // UpdateReleaseSyncPoint() creates a new sync_point using |gl_helper|, so
80 // wait the given |sync_point| using |gl_helper|.
81 if (gl_helper) {
82 gl_helper->WaitSyncPoint(sync_point);
83 SyncPointClientImpl client(gl_helper);
84 video_frame->UpdateReleaseSyncPoint(&client);
86 #endif
89 } // anonymous namespace
91 struct VideoCaptureController::ControllerClient {
92 ControllerClient(const VideoCaptureControllerID& id,
93 VideoCaptureControllerEventHandler* handler,
94 base::ProcessHandle render_process,
95 media::VideoCaptureSessionId session_id,
96 const media::VideoCaptureParams& params)
97 : controller_id(id),
98 event_handler(handler),
99 render_process_handle(render_process),
100 session_id(session_id),
101 parameters(params),
102 session_closed(false),
103 paused(false) {}
105 ~ControllerClient() {}
107 // ID used for identifying this object.
108 const VideoCaptureControllerID controller_id;
109 VideoCaptureControllerEventHandler* const event_handler;
111 // Handle to the render process that will receive the capture buffers.
112 const base::ProcessHandle render_process_handle;
113 const media::VideoCaptureSessionId session_id;
114 const media::VideoCaptureParams parameters;
116 // Buffers that are currently known to this client.
117 std::set<int> known_buffers;
119 // Buffers currently held by this client, and syncpoint callback to call when
120 // they are returned from the client.
121 typedef std::map<int, scoped_refptr<media::VideoFrame> > ActiveBufferMap;
122 ActiveBufferMap active_buffers;
124 // State of capture session, controlled by VideoCaptureManager directly. This
125 // transitions to true as soon as StopSession() occurs, at which point the
126 // client is sent an OnEnded() event. However, because the client retains a
127 // VideoCaptureController* pointer, its ControllerClient entry lives on until
128 // it unregisters itself via RemoveClient(), which may happen asynchronously.
130 // TODO(nick): If we changed the semantics of VideoCaptureHost so that
131 // OnEnded() events were processed synchronously (with the RemoveClient() done
132 // implicitly), we could avoid tracking this state here in the Controller, and
133 // simplify the code in both places.
134 bool session_closed;
136 // Indicates whether the client is paused, if true, VideoCaptureController
137 // stops updating its buffer.
138 bool paused;
141 // Receives events from the VideoCaptureDevice and posts them to a
142 // VideoCaptureController on the IO thread. An instance of this class may safely
143 // outlive its target VideoCaptureController.
145 // Methods of this class may be called from any thread, and in practice will
146 // often be called on some auxiliary thread depending on the platform and the
147 // device type; including, for example, the DirectShow thread on Windows, the
148 // v4l2_thread on Linux, and the UI thread for tab capture.
149 class VideoCaptureController::VideoCaptureDeviceClient
150 : public media::VideoCaptureDevice::Client {
151 public:
152 explicit VideoCaptureDeviceClient(
153 const base::WeakPtr<VideoCaptureController>& controller,
154 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
155 ~VideoCaptureDeviceClient() override;
157 // VideoCaptureDevice::Client implementation.
158 scoped_refptr<Buffer> ReserveOutputBuffer(media::VideoFrame::Format format,
159 const gfx::Size& size) override;
160 void OnIncomingCapturedData(const uint8* data,
161 int length,
162 const VideoCaptureFormat& frame_format,
163 int rotation,
164 base::TimeTicks timestamp) override;
165 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 void OnError(const std::string& reason) override;
171 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 has_received_frames_(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::PauseOrResumeClient(
273 const VideoCaptureControllerID& id,
274 VideoCaptureControllerEventHandler* event_handler,
275 bool pause) {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 DVLOG(1) << "VideoCaptureController::PauseOrResumeClient, id "
278 << id.device_id << ", " << pause;
280 ControllerClient* client = FindClient(id, event_handler, controller_clients_);
281 if (!client)
282 return;
284 DCHECK(client->paused != pause);
285 client->paused = pause;
288 void VideoCaptureController::StopSession(int session_id) {
289 DCHECK_CURRENTLY_ON(BrowserThread::IO);
290 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
292 ControllerClient* client = FindClient(session_id, controller_clients_);
294 if (client) {
295 client->session_closed = true;
296 client->event_handler->OnEnded(client->controller_id);
300 void VideoCaptureController::ReturnBuffer(
301 const VideoCaptureControllerID& id,
302 VideoCaptureControllerEventHandler* event_handler,
303 int buffer_id,
304 uint32 sync_point) {
305 DCHECK_CURRENTLY_ON(BrowserThread::IO);
307 ControllerClient* client = FindClient(id, event_handler, controller_clients_);
309 // If this buffer is not held by this client, or this client doesn't exist
310 // in controller, do nothing.
311 ControllerClient::ActiveBufferMap::iterator iter;
312 if (!client || (iter = client->active_buffers.find(buffer_id)) ==
313 client->active_buffers.end()) {
314 NOTREACHED();
315 return;
317 scoped_refptr<media::VideoFrame> frame = iter->second;
318 client->active_buffers.erase(iter);
319 buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
321 #if defined(OS_ANDROID)
322 DCHECK_EQ(0u, sync_point);
323 #endif
324 if (sync_point)
325 BrowserThread::PostTask(BrowserThread::UI,
326 FROM_HERE,
327 base::Bind(&ReturnVideoFrame, frame, sync_point));
330 const media::VideoCaptureFormat&
331 VideoCaptureController::GetVideoCaptureFormat() const {
332 DCHECK_CURRENTLY_ON(BrowserThread::IO);
333 return video_capture_format_;
336 scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
337 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
338 media::VideoFrame::Format format,
339 const gfx::Size& size) {
340 return DoReserveOutputBuffer(format, size);
343 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
344 const uint8* data,
345 int length,
346 const VideoCaptureFormat& frame_format,
347 int rotation,
348 base::TimeTicks timestamp) {
349 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData");
351 if (!frame_format.IsValid())
352 return;
354 // Chopped pixels in width/height in case video capture device has odd
355 // numbers for width/height.
356 int chopped_width = 0;
357 int chopped_height = 0;
358 int new_unrotated_width = frame_format.frame_size.width();
359 int new_unrotated_height = frame_format.frame_size.height();
361 if (new_unrotated_width & 1) {
362 --new_unrotated_width;
363 chopped_width = 1;
365 if (new_unrotated_height & 1) {
366 --new_unrotated_height;
367 chopped_height = 1;
370 int destination_width = new_unrotated_width;
371 int destination_height = new_unrotated_height;
372 if (rotation == 90 || rotation == 270) {
373 destination_width = new_unrotated_height;
374 destination_height = new_unrotated_width;
376 const gfx::Size dimensions(destination_width, destination_height);
377 if (!media::VideoFrame::IsValidConfig(media::VideoFrame::I420,
378 dimensions,
379 gfx::Rect(dimensions),
380 dimensions)) {
381 return;
384 scoped_refptr<Buffer> buffer =
385 DoReserveOutputBuffer(media::VideoFrame::I420, dimensions);
387 if (!buffer.get())
388 return;
389 uint8* yplane = NULL;
390 bool flip = false;
391 yplane = reinterpret_cast<uint8*>(buffer->data());
392 uint8* uplane =
393 yplane +
394 media::VideoFrame::PlaneAllocationSize(
395 media::VideoFrame::I420, media::VideoFrame::kYPlane, dimensions);
396 uint8* vplane =
397 uplane +
398 media::VideoFrame::PlaneAllocationSize(
399 media::VideoFrame::I420, media::VideoFrame::kUPlane, dimensions);
400 int yplane_stride = dimensions.width();
401 int uv_plane_stride = yplane_stride / 2;
402 int crop_x = 0;
403 int crop_y = 0;
404 libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
406 libyuv::RotationMode rotation_mode = libyuv::kRotate0;
407 if (rotation == 90)
408 rotation_mode = libyuv::kRotate90;
409 else if (rotation == 180)
410 rotation_mode = libyuv::kRotate180;
411 else if (rotation == 270)
412 rotation_mode = libyuv::kRotate270;
414 switch (frame_format.pixel_format) {
415 case media::PIXEL_FORMAT_UNKNOWN: // Color format not set.
416 break;
417 case media::PIXEL_FORMAT_I420:
418 DCHECK(!chopped_width && !chopped_height);
419 origin_colorspace = libyuv::FOURCC_I420;
420 break;
421 case media::PIXEL_FORMAT_YV12:
422 DCHECK(!chopped_width && !chopped_height);
423 origin_colorspace = libyuv::FOURCC_YV12;
424 break;
425 case media::PIXEL_FORMAT_NV12:
426 DCHECK(!chopped_width && !chopped_height);
427 origin_colorspace = libyuv::FOURCC_NV12;
428 break;
429 case media::PIXEL_FORMAT_NV21:
430 DCHECK(!chopped_width && !chopped_height);
431 origin_colorspace = libyuv::FOURCC_NV21;
432 break;
433 case media::PIXEL_FORMAT_YUY2:
434 DCHECK(!chopped_width && !chopped_height);
435 origin_colorspace = libyuv::FOURCC_YUY2;
436 break;
437 case media::PIXEL_FORMAT_UYVY:
438 DCHECK(!chopped_width && !chopped_height);
439 origin_colorspace = libyuv::FOURCC_UYVY;
440 break;
441 case media::PIXEL_FORMAT_RGB24:
442 origin_colorspace = libyuv::FOURCC_24BG;
443 #if defined(OS_WIN)
444 // TODO(wjia): Currently, for RGB24 on WIN, capture device always
445 // passes in positive src_width and src_height. Remove this hardcoded
446 // value when nagative src_height is supported. The negative src_height
447 // indicates that vertical flipping is needed.
448 flip = true;
449 #endif
450 break;
451 case media::PIXEL_FORMAT_ARGB:
452 origin_colorspace = libyuv::FOURCC_ARGB;
453 break;
454 case media::PIXEL_FORMAT_MJPEG:
455 origin_colorspace = libyuv::FOURCC_MJPG;
456 break;
457 default:
458 NOTREACHED();
461 libyuv::ConvertToI420(data,
462 length,
463 yplane,
464 yplane_stride,
465 uplane,
466 uv_plane_stride,
467 vplane,
468 uv_plane_stride,
469 crop_x,
470 crop_y,
471 frame_format.frame_size.width(),
472 (flip ? -frame_format.frame_size.height() :
473 frame_format.frame_size.height()),
474 new_unrotated_width,
475 new_unrotated_height,
476 rotation_mode,
477 origin_colorspace);
478 scoped_refptr<media::VideoFrame> frame =
479 media::VideoFrame::WrapExternalPackedMemory(
480 media::VideoFrame::I420,
481 dimensions,
482 gfx::Rect(dimensions),
483 dimensions,
484 yplane,
485 media::VideoFrame::AllocationSize(media::VideoFrame::I420,
486 dimensions),
487 base::SharedMemory::NULLHandle(),
488 base::TimeDelta(),
489 base::Closure());
490 DCHECK(frame.get());
492 VideoCaptureFormat format(
493 dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420);
494 BrowserThread::PostTask(
495 BrowserThread::IO,
496 FROM_HERE,
497 base::Bind(
498 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
499 controller_,
500 buffer,
501 format,
502 frame,
503 timestamp));
506 void
507 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
508 const scoped_refptr<Buffer>& buffer,
509 const VideoCaptureFormat& buffer_format,
510 const scoped_refptr<media::VideoFrame>& frame,
511 base::TimeTicks timestamp) {
512 BrowserThread::PostTask(
513 BrowserThread::IO,
514 FROM_HERE,
515 base::Bind(
516 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
517 controller_,
518 buffer,
519 buffer_format,
520 frame,
521 timestamp));
524 void VideoCaptureController::VideoCaptureDeviceClient::OnError(
525 const std::string& reason) {
526 const std::string log_message = base::StringPrintf(
527 "Error on video capture: %s, OS message: %s",
528 reason.c_str(),
529 logging::SystemErrorCodeToString(
530 logging::GetLastSystemErrorCode()).c_str());
531 DLOG(ERROR) << log_message;
532 MediaStreamManager::SendMessageToNativeLog(log_message);
533 BrowserThread::PostTask(BrowserThread::IO,
534 FROM_HERE,
535 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
538 void VideoCaptureController::VideoCaptureDeviceClient::OnLog(
539 const std::string& message) {
540 MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
543 scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
544 VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
545 media::VideoFrame::Format format,
546 const gfx::Size& dimensions) {
547 size_t frame_bytes = 0;
548 if (format == media::VideoFrame::NATIVE_TEXTURE) {
549 DCHECK_EQ(dimensions.width(), 0);
550 DCHECK_EQ(dimensions.height(), 0);
551 } else {
552 // The capture pipeline expects I420 for now.
553 DCHECK_EQ(format, media::VideoFrame::I420)
554 << "Non-I420 output buffer format " << format << " requested";
555 frame_bytes = media::VideoFrame::AllocationSize(format, dimensions);
558 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
559 int buffer_id =
560 buffer_pool_->ReserveForProducer(frame_bytes, &buffer_id_to_drop);
561 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
562 return NULL;
563 void* data;
564 size_t size;
565 buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
567 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
568 new PoolBuffer(buffer_pool_, buffer_id, data, size));
570 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
571 BrowserThread::PostTask(BrowserThread::IO,
572 FROM_HERE,
573 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
574 controller_, buffer_id_to_drop));
577 return output_buffer;
580 VideoCaptureController::~VideoCaptureController() {
581 STLDeleteContainerPointers(controller_clients_.begin(),
582 controller_clients_.end());
585 void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
586 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
587 const media::VideoCaptureFormat& buffer_format,
588 const scoped_refptr<media::VideoFrame>& frame,
589 base::TimeTicks timestamp) {
590 DCHECK_CURRENTLY_ON(BrowserThread::IO);
591 DCHECK_NE(buffer->id(), VideoCaptureBufferPool::kInvalidId);
593 int count = 0;
594 if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
595 for (ControllerClients::iterator client_it = controller_clients_.begin();
596 client_it != controller_clients_.end(); ++client_it) {
597 ControllerClient* client = *client_it;
598 if (client->session_closed || client->paused)
599 continue;
601 if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
602 client->event_handler->OnMailboxBufferReady(client->controller_id,
603 buffer->id(),
604 *frame->mailbox_holder(),
605 buffer_format,
606 timestamp);
607 } else {
608 bool is_new_buffer = client->known_buffers.insert(buffer->id()).second;
609 if (is_new_buffer) {
610 // On the first use of a buffer on a client, share the memory handle.
611 size_t memory_size = 0;
612 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
613 buffer->id(), client->render_process_handle, &memory_size);
614 client->event_handler->OnBufferCreated(
615 client->controller_id, remote_handle, memory_size, buffer->id());
618 client->event_handler->OnBufferReady(
619 client->controller_id, buffer->id(), buffer_format,
620 frame->visible_rect(), timestamp);
623 bool inserted =
624 client->active_buffers.insert(std::make_pair(buffer->id(), frame))
625 .second;
626 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer->id();
627 count++;
631 if (!has_received_frames_) {
632 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
633 buffer_format.frame_size.width());
634 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
635 buffer_format.frame_size.height());
636 UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
637 buffer_format.frame_size.width(),
638 buffer_format.frame_size.height());
639 UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate",
640 buffer_format.frame_rate);
641 has_received_frames_ = true;
644 buffer_pool_->HoldForConsumers(buffer->id(), count);
647 void VideoCaptureController::DoErrorOnIOThread() {
648 DCHECK_CURRENTLY_ON(BrowserThread::IO);
649 state_ = VIDEO_CAPTURE_STATE_ERROR;
651 for (ControllerClients::iterator client_it = controller_clients_.begin();
652 client_it != controller_clients_.end(); ++client_it) {
653 ControllerClient* client = *client_it;
654 if (client->session_closed)
655 continue;
657 client->event_handler->OnError(client->controller_id);
661 void VideoCaptureController::DoBufferDestroyedOnIOThread(
662 int buffer_id_to_drop) {
663 DCHECK_CURRENTLY_ON(BrowserThread::IO);
665 for (ControllerClients::iterator client_it = controller_clients_.begin();
666 client_it != controller_clients_.end(); ++client_it) {
667 ControllerClient* client = *client_it;
668 if (client->session_closed)
669 continue;
671 if (client->known_buffers.erase(buffer_id_to_drop)) {
672 client->event_handler->OnBufferDestroyed(client->controller_id,
673 buffer_id_to_drop);
678 VideoCaptureController::ControllerClient*
679 VideoCaptureController::FindClient(
680 const VideoCaptureControllerID& id,
681 VideoCaptureControllerEventHandler* handler,
682 const ControllerClients& clients) {
683 for (ControllerClients::const_iterator client_it = clients.begin();
684 client_it != clients.end(); ++client_it) {
685 if ((*client_it)->controller_id == id &&
686 (*client_it)->event_handler == handler) {
687 return *client_it;
690 return NULL;
693 VideoCaptureController::ControllerClient*
694 VideoCaptureController::FindClient(
695 int session_id,
696 const ControllerClients& clients) {
697 for (ControllerClients::const_iterator client_it = clients.begin();
698 client_it != clients.end(); ++client_it) {
699 if ((*client_it)->session_id == session_id) {
700 return *client_it;
703 return NULL;
706 int VideoCaptureController::GetClientCount() const {
707 DCHECK_CURRENTLY_ON(BrowserThread::IO);
708 return controller_clients_.size();
711 int VideoCaptureController::GetActiveClientCount() const {
712 DCHECK_CURRENTLY_ON(BrowserThread::IO);
713 int active_client_count = 0;
714 for (ControllerClient* client : controller_clients_) {
715 if (!client->paused)
716 ++active_client_count;
718 return active_client_count;
721 } // namespace content