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