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