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 <set>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/stl_util.h"
     12 #include "content/browser/renderer_host/media/media_stream_manager.h"
     13 #include "content/browser/renderer_host/media/video_capture_manager.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "media/base/video_frame.h"
     16 #include "media/base/video_util.h"
     17 #include "media/base/yuv_convert.h"
     18 
     19 #if !defined(OS_IOS) && !defined(OS_ANDROID)
     20 #include "third_party/libyuv/include/libyuv.h"
     21 #endif
     22 
     23 namespace {
     24 
     25 // TODO(wjia): Support stride.
     26 void RotatePackedYV12Frame(
     27     const uint8* src,
     28     uint8* dest_yplane,
     29     uint8* dest_uplane,
     30     uint8* dest_vplane,
     31     int width,
     32     int height,
     33     int rotation,
     34     bool flip_vert,
     35     bool flip_horiz) {
     36   media::RotatePlaneByPixels(
     37       src, dest_yplane, width, height, rotation, flip_vert, flip_horiz);
     38   int y_size = width * height;
     39   src += y_size;
     40   media::RotatePlaneByPixels(
     41       src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz);
     42   src += y_size/4;
     43   media::RotatePlaneByPixels(
     44       src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz);
     45 }
     46 
     47 }  // namespace
     48 
     49 namespace content {
     50 
     51 // The number of buffers that VideoCaptureBufferPool should allocate.
     52 static const int kNoOfBuffers = 3;
     53 
     54 struct VideoCaptureController::ControllerClient {
     55   ControllerClient(
     56       const VideoCaptureControllerID& id,
     57       VideoCaptureControllerEventHandler* handler,
     58       base::ProcessHandle render_process,
     59       const media::VideoCaptureParams& params)
     60       : controller_id(id),
     61         event_handler(handler),
     62         render_process_handle(render_process),
     63         parameters(params),
     64         session_closed(false) {
     65   }
     66 
     67   ~ControllerClient() {}
     68 
     69   // ID used for identifying this object.
     70   VideoCaptureControllerID controller_id;
     71   VideoCaptureControllerEventHandler* event_handler;
     72 
     73   // Handle to the render process that will receive the capture buffers.
     74   base::ProcessHandle render_process_handle;
     75   media::VideoCaptureParams parameters;
     76 
     77   // Buffers used by this client.
     78   std::set<int> buffers;
     79 
     80   // State of capture session, controlled by VideoCaptureManager directly.
     81   bool session_closed;
     82 };
     83 
     84 VideoCaptureController::VideoCaptureController(
     85     VideoCaptureManager* video_capture_manager)
     86     : chopped_width_(0),
     87       chopped_height_(0),
     88       frame_info_available_(false),
     89       video_capture_manager_(video_capture_manager),
     90       device_in_use_(false),
     91       state_(VIDEO_CAPTURE_STATE_STOPPED) {
     92   memset(&current_params_, 0, sizeof(current_params_));
     93 }
     94 
     95 void VideoCaptureController::StartCapture(
     96     const VideoCaptureControllerID& id,
     97     VideoCaptureControllerEventHandler* event_handler,
     98     base::ProcessHandle render_process,
     99     const media::VideoCaptureParams& params) {
    100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    101   DVLOG(1) << "VideoCaptureController::StartCapture, id " << id.device_id
    102            << ", (" << params.width
    103            << ", " << params.height
    104            << ", " << params.frame_per_second
    105            << ", " << params.session_id
    106            << ")";
    107 
    108   // Signal error in case device is already in error state.
    109   if (state_ == VIDEO_CAPTURE_STATE_ERROR) {
    110     event_handler->OnError(id);
    111     return;
    112   }
    113 
    114   // Do nothing if this client has called StartCapture before.
    115   if (FindClient(id, event_handler, controller_clients_) ||
    116       FindClient(id, event_handler, pending_clients_))
    117     return;
    118 
    119   ControllerClient* client = new ControllerClient(id, event_handler,
    120                                                   render_process, params);
    121   // In case capture has been started, need to check different conditions.
    122   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
    123   // TODO(wjia): Temporarily disable restarting till client supports resampling.
    124 #if 0
    125     // This client has higher resolution than what is currently requested.
    126     // Need restart capturing.
    127     if (params.width > current_params_.width ||
    128         params.height > current_params_.height) {
    129       video_capture_manager_->Stop(current_params_.session_id,
    130           base::Bind(&VideoCaptureController::OnDeviceStopped, this));
    131       frame_info_available_ = false;
    132       state_ = VIDEO_CAPTURE_STATE_STOPPING;
    133       pending_clients_.push_back(client);
    134       return;
    135     }
    136 #endif
    137 
    138     // This client's resolution is no larger than what's currently requested.
    139     // When frame_info has been returned by device, send them to client.
    140     if (frame_info_available_) {
    141       SendFrameInfoAndBuffers(client);
    142     }
    143     controller_clients_.push_back(client);
    144     return;
    145   }
    146 
    147   // In case the device is in the middle of stopping, put the client in
    148   // pending queue.
    149   if (state_ == VIDEO_CAPTURE_STATE_STOPPING) {
    150     pending_clients_.push_back(client);
    151     return;
    152   }
    153 
    154   // Fresh start.
    155   controller_clients_.push_back(client);
    156   current_params_ = params;
    157   // Order the manager to start the actual capture.
    158   video_capture_manager_->Start(params, this);
    159   state_ = VIDEO_CAPTURE_STATE_STARTED;
    160   device_in_use_ = true;
    161 }
    162 
    163 void VideoCaptureController::StopCapture(
    164     const VideoCaptureControllerID& id,
    165     VideoCaptureControllerEventHandler* event_handler) {
    166   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    167   DVLOG(1) << "VideoCaptureController::StopCapture, id " << id.device_id;
    168 
    169   ControllerClient* client = FindClient(id, event_handler, pending_clients_);
    170   // If the client is still in pending queue, just remove it.
    171   if (client) {
    172     pending_clients_.remove(client);
    173     return;
    174   }
    175 
    176   client = FindClient(id, event_handler, controller_clients_);
    177   if (!client)
    178     return;
    179 
    180   // Take back all buffers held by the |client|.
    181   if (buffer_pool_.get()) {
    182     for (std::set<int>::iterator buffer_it = client->buffers.begin();
    183          buffer_it != client->buffers.end();
    184          ++buffer_it) {
    185       int buffer_id = *buffer_it;
    186       buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
    187     }
    188   }
    189   client->buffers.clear();
    190 
    191   int session_id = client->parameters.session_id;
    192   delete client;
    193   controller_clients_.remove(client);
    194 
    195   // No more clients. Stop device.
    196   if (controller_clients_.empty() &&
    197       (state_ == VIDEO_CAPTURE_STATE_STARTED ||
    198        state_ == VIDEO_CAPTURE_STATE_ERROR)) {
    199     video_capture_manager_->Stop(session_id,
    200         base::Bind(&VideoCaptureController::OnDeviceStopped, this));
    201     frame_info_available_ = false;
    202     state_ = VIDEO_CAPTURE_STATE_STOPPING;
    203   }
    204 }
    205 
    206 void VideoCaptureController::StopSession(
    207     int session_id) {
    208   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    209   DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
    210 
    211   ControllerClient* client = FindClient(session_id, pending_clients_);
    212   if (!client)
    213     client = FindClient(session_id, controller_clients_);
    214 
    215   if (client) {
    216     client->session_closed = true;
    217     client->event_handler->OnEnded(client->controller_id);
    218   }
    219 }
    220 
    221 void VideoCaptureController::ReturnBuffer(
    222     const VideoCaptureControllerID& id,
    223     VideoCaptureControllerEventHandler* event_handler,
    224     int buffer_id) {
    225   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    226 
    227   ControllerClient* client = FindClient(id, event_handler,
    228                                         controller_clients_);
    229 
    230   // If this buffer is not held by this client, or this client doesn't exist
    231   // in controller, do nothing.
    232   if (!client ||
    233       client->buffers.find(buffer_id) == client->buffers.end())
    234     return;
    235 
    236   client->buffers.erase(buffer_id);
    237   buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
    238 
    239   // When all buffers have been returned by clients and device has been
    240   // called to stop, check if restart is needed. This could happen when
    241   // capture needs to be restarted due to resolution change.
    242   if (!buffer_pool_->IsAnyBufferHeldForConsumers() &&
    243       state_ == VIDEO_CAPTURE_STATE_STOPPING) {
    244     PostStopping();
    245   }
    246 }
    247 
    248 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() {
    249   base::AutoLock lock(buffer_pool_lock_);
    250   if (!buffer_pool_.get())
    251     return NULL;
    252   return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
    253                                                        frame_info_.height),
    254                                              0);
    255 }
    256 
    257 // Implements VideoCaptureDevice::EventHandler.
    258 // OnIncomingCapturedFrame is called the thread running the capture device.
    259 // I.e.- DirectShow thread on windows and v4l2_thread on Linux.
    260 void VideoCaptureController::OnIncomingCapturedFrame(
    261     const uint8* data,
    262     int length,
    263     base::Time timestamp,
    264     int rotation,
    265     bool flip_vert,
    266     bool flip_horiz) {
    267   DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 ||
    268          frame_info_.color == media::VideoCaptureCapability::kYV12 ||
    269          (rotation == 0 && !flip_vert && !flip_horiz));
    270 
    271   scoped_refptr<media::VideoFrame> dst;
    272   {
    273     base::AutoLock lock(buffer_pool_lock_);
    274     if (!buffer_pool_.get())
    275       return;
    276     dst = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
    277                                                         frame_info_.height),
    278                                               rotation);
    279   }
    280 
    281   if (!dst.get())
    282     return;
    283 
    284   uint8* yplane = dst->data(media::VideoFrame::kYPlane);
    285   uint8* uplane = dst->data(media::VideoFrame::kUPlane);
    286   uint8* vplane = dst->data(media::VideoFrame::kVPlane);
    287 
    288   // Do color conversion from the camera format to I420.
    289   switch (frame_info_.color) {
    290     case media::VideoCaptureCapability::kColorUnknown:  // Color format not set.
    291       break;
    292     case media::VideoCaptureCapability::kI420:
    293       DCHECK(!chopped_width_ && !chopped_height_);
    294       RotatePackedYV12Frame(
    295           data, yplane, uplane, vplane, frame_info_.width, frame_info_.height,
    296           rotation, flip_vert, flip_horiz);
    297       break;
    298     case media::VideoCaptureCapability::kYV12:
    299       DCHECK(!chopped_width_ && !chopped_height_);
    300       RotatePackedYV12Frame(
    301           data, yplane, vplane, uplane, frame_info_.width, frame_info_.height,
    302           rotation, flip_vert, flip_horiz);
    303       break;
    304     case media::VideoCaptureCapability::kNV21:
    305       DCHECK(!chopped_width_ && !chopped_height_);
    306       media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width,
    307                               frame_info_.height);
    308       break;
    309     case media::VideoCaptureCapability::kYUY2:
    310       DCHECK(!chopped_width_ && !chopped_height_);
    311       if (frame_info_.width * frame_info_.height * 2 != length) {
    312         // If |length| of |data| does not match the expected width and height
    313         // we can't convert the frame to I420. YUY2 is 2 bytes per pixel.
    314         break;
    315       }
    316 
    317       media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width,
    318                               frame_info_.height);
    319       break;
    320     case media::VideoCaptureCapability::kRGB24: {
    321       int ystride = frame_info_.width;
    322       int uvstride = frame_info_.width / 2;
    323 #if defined(OS_WIN)  // RGB on Windows start at the bottom line.
    324       int rgb_stride = -3 * (frame_info_.width + chopped_width_);
    325       const uint8* rgb_src = data + 3 * (frame_info_.width + chopped_width_) *
    326           (frame_info_.height -1 + chopped_height_);
    327 #else
    328       int rgb_stride = 3 * (frame_info_.width + chopped_width_);
    329       const uint8* rgb_src = data;
    330 #endif
    331       media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane,
    332                                frame_info_.width, frame_info_.height,
    333                                rgb_stride, ystride, uvstride);
    334       break;
    335     }
    336     case media::VideoCaptureCapability::kARGB:
    337       media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width,
    338                                frame_info_.height,
    339                                (frame_info_.width + chopped_width_) * 4,
    340                                frame_info_.width, frame_info_.width / 2);
    341       break;
    342 #if !defined(OS_IOS) && !defined(OS_ANDROID)
    343     case media::VideoCaptureCapability::kMJPEG: {
    344       int yplane_stride = frame_info_.width;
    345       int uv_plane_stride = (frame_info_.width + 1) / 2;
    346       int crop_x = 0;
    347       int crop_y = 0;
    348       libyuv::ConvertToI420(data, length, yplane, yplane_stride, uplane,
    349                             uv_plane_stride, vplane, uv_plane_stride, crop_x,
    350                             crop_y, frame_info_.width, frame_info_.height,
    351                             frame_info_.width, frame_info_.height,
    352                             libyuv::kRotate0, libyuv::FOURCC_MJPG);
    353       break;
    354     }
    355 #endif
    356     default:
    357       NOTREACHED();
    358   }
    359 
    360   BrowserThread::PostTask(BrowserThread::IO,
    361       FROM_HERE,
    362       base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
    363                  this, dst, timestamp));
    364 }
    365 
    366 // OnIncomingCapturedVideoFrame is called the thread running the capture device.
    367 void VideoCaptureController::OnIncomingCapturedVideoFrame(
    368     const scoped_refptr<media::VideoFrame>& frame,
    369     base::Time timestamp) {
    370 
    371   scoped_refptr<media::VideoFrame> target;
    372   {
    373     base::AutoLock lock(buffer_pool_lock_);
    374 
    375     if (!buffer_pool_.get())
    376       return;
    377 
    378     // If this is a frame that belongs to the buffer pool, we can forward it
    379     // directly to the IO thread and be done.
    380     if (buffer_pool_->RecognizeReservedBuffer(
    381         frame->shared_memory_handle()) >= 0) {
    382       BrowserThread::PostTask(BrowserThread::IO,
    383           FROM_HERE,
    384           base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
    385                      this, frame, timestamp));
    386       return;
    387     }
    388     // Otherwise, this is a frame that belongs to the caller, and we must copy
    389     // it to a frame from the buffer pool.
    390     target = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
    391                                                            frame_info_.height),
    392                                                  0);
    393   }
    394 
    395   if (!target.get())
    396     return;
    397 
    398   // Validate the inputs.
    399   if (frame->coded_size() != target->coded_size())
    400     return;  // Only exact copies are supported.
    401   if (!(frame->format() == media::VideoFrame::I420 ||
    402         frame->format() == media::VideoFrame::YV12 ||
    403         frame->format() == media::VideoFrame::RGB32)) {
    404     NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame";
    405     return;
    406   }
    407 
    408   const int kYPlane = media::VideoFrame::kYPlane;
    409   const int kUPlane = media::VideoFrame::kUPlane;
    410   const int kVPlane = media::VideoFrame::kVPlane;
    411   const int kAPlane = media::VideoFrame::kAPlane;
    412   const int kRGBPlane = media::VideoFrame::kRGBPlane;
    413 
    414   // Do color conversion from the camera format to I420.
    415   switch (frame->format()) {
    416 #if defined(GOOGLE_TV)
    417     case media::VideoFrame::HOLE:
    418       // Fall-through to NOTREACHED() block.
    419 #endif
    420     case media::VideoFrame::INVALID:
    421     case media::VideoFrame::YV16:
    422     case media::VideoFrame::EMPTY:
    423     case media::VideoFrame::NATIVE_TEXTURE: {
    424       NOTREACHED();
    425       break;
    426     }
    427     case media::VideoFrame::I420:
    428     case media::VideoFrame::YV12: {
    429       DCHECK(!chopped_width_ && !chopped_height_);
    430       media::CopyYPlane(frame->data(kYPlane),
    431                         frame->stride(kYPlane),
    432                         frame->rows(kYPlane),
    433                         target.get());
    434       media::CopyUPlane(frame->data(kUPlane),
    435                         frame->stride(kUPlane),
    436                         frame->rows(kUPlane),
    437                         target.get());
    438       media::CopyVPlane(frame->data(kVPlane),
    439                         frame->stride(kVPlane),
    440                         frame->rows(kVPlane),
    441                         target.get());
    442       break;
    443     }
    444     case media::VideoFrame::YV12A: {
    445       DCHECK(!chopped_width_ && !chopped_height_);
    446       media::CopyYPlane(frame->data(kYPlane),
    447                         frame->stride(kYPlane),
    448                         frame->rows(kYPlane),
    449                         target.get());
    450       media::CopyUPlane(frame->data(kUPlane),
    451                         frame->stride(kUPlane),
    452                         frame->rows(kUPlane),
    453                         target.get());
    454       media::CopyVPlane(frame->data(kVPlane),
    455                         frame->stride(kVPlane),
    456                         frame->rows(kVPlane),
    457                         target.get());
    458       media::CopyAPlane(frame->data(kAPlane),
    459                         frame->stride(kAPlane),
    460                         frame->rows(kAPlane),
    461                         target.get());
    462       break;
    463     }
    464     case media::VideoFrame::RGB32: {
    465       media::ConvertRGB32ToYUV(frame->data(kRGBPlane),
    466                                target->data(kYPlane),
    467                                target->data(kUPlane),
    468                                target->data(kVPlane),
    469                                target->coded_size().width(),
    470                                target->coded_size().height(),
    471                                frame->stride(kRGBPlane),
    472                                target->stride(kYPlane),
    473                                target->stride(kUPlane));
    474       break;
    475     }
    476   }
    477 
    478   BrowserThread::PostTask(BrowserThread::IO,
    479       FROM_HERE,
    480       base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
    481                  this, target, timestamp));
    482 }
    483 
    484 void VideoCaptureController::OnError() {
    485   BrowserThread::PostTask(BrowserThread::IO,
    486       FROM_HERE,
    487       base::Bind(&VideoCaptureController::DoErrorOnIOThread, this));
    488 }
    489 
    490 void VideoCaptureController::OnFrameInfo(
    491     const media::VideoCaptureCapability& info) {
    492   frame_info_= info;
    493   // Handle cases when |info| has odd numbers for width/height.
    494   if (info.width & 1) {
    495     --frame_info_.width;
    496     chopped_width_ = 1;
    497   } else {
    498     chopped_width_ = 0;
    499   }
    500   if (info.height & 1) {
    501     --frame_info_.height;
    502     chopped_height_ = 1;
    503   } else {
    504     chopped_height_ = 0;
    505   }
    506   BrowserThread::PostTask(BrowserThread::IO,
    507       FROM_HERE,
    508       base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this));
    509 }
    510 
    511 void VideoCaptureController::OnFrameInfoChanged(
    512     const media::VideoCaptureCapability& info) {
    513   BrowserThread::PostTask(BrowserThread::IO,
    514       FROM_HERE,
    515       base::Bind(&VideoCaptureController::DoFrameInfoChangedOnIOThread,
    516                  this, info));
    517 }
    518 
    519 VideoCaptureController::~VideoCaptureController() {
    520   buffer_pool_ = NULL;  // Release all buffers.
    521   STLDeleteContainerPointers(controller_clients_.begin(),
    522                              controller_clients_.end());
    523   STLDeleteContainerPointers(pending_clients_.begin(),
    524                              pending_clients_.end());
    525 }
    526 
    527 // Called by VideoCaptureManager when a device have been stopped.
    528 void VideoCaptureController::OnDeviceStopped() {
    529   BrowserThread::PostTask(BrowserThread::IO,
    530       FROM_HERE,
    531       base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this));
    532 }
    533 
    534 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
    535     const scoped_refptr<media::VideoFrame>& reserved_frame,
    536     base::Time timestamp) {
    537   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    538 
    539   if (!buffer_pool_.get())
    540     return;
    541 
    542   int buffer_id = buffer_pool_->RecognizeReservedBuffer(
    543       reserved_frame->shared_memory_handle());
    544   if (buffer_id < 0) {
    545     NOTREACHED();
    546     return;
    547   }
    548 
    549   int count = 0;
    550   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
    551     for (ControllerClients::iterator client_it = controller_clients_.begin();
    552          client_it != controller_clients_.end(); ++client_it) {
    553       if ((*client_it)->session_closed)
    554         continue;
    555 
    556       (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id,
    557                                                  buffer_id, timestamp);
    558       (*client_it)->buffers.insert(buffer_id);
    559       count++;
    560     }
    561   }
    562 
    563   buffer_pool_->HoldForConsumers(buffer_id, count);
    564 }
    565 
    566 void VideoCaptureController::DoFrameInfoOnIOThread() {
    567   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    568   DCHECK(!buffer_pool_.get())
    569       << "Device is restarted without releasing shared memory.";
    570 
    571   // Allocate memory only when device has been started.
    572   if (state_ != VIDEO_CAPTURE_STATE_STARTED)
    573     return;
    574 
    575   scoped_refptr<VideoCaptureBufferPool> buffer_pool =
    576       new VideoCaptureBufferPool(frame_info_.width * frame_info_.height * 3 / 2,
    577                                  kNoOfBuffers);
    578 
    579   // Check whether all buffers were created successfully.
    580   if (!buffer_pool->Allocate()) {
    581     state_ = VIDEO_CAPTURE_STATE_ERROR;
    582     for (ControllerClients::iterator client_it = controller_clients_.begin();
    583          client_it != controller_clients_.end(); ++client_it) {
    584       (*client_it)->event_handler->OnError((*client_it)->controller_id);
    585     }
    586     return;
    587   }
    588 
    589   {
    590     base::AutoLock lock(buffer_pool_lock_);
    591     buffer_pool_ = buffer_pool;
    592   }
    593   frame_info_available_ = true;
    594 
    595   for (ControllerClients::iterator client_it = controller_clients_.begin();
    596        client_it != controller_clients_.end(); ++client_it) {
    597     SendFrameInfoAndBuffers(*client_it);
    598   }
    599 }
    600 
    601 void VideoCaptureController::DoFrameInfoChangedOnIOThread(
    602     const media::VideoCaptureCapability& info) {
    603   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    604   // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if
    605   // needed, to support the new video capture format. See crbug.com/266082.
    606   for (ControllerClients::iterator client_it = controller_clients_.begin();
    607        client_it != controller_clients_.end(); ++client_it) {
    608     (*client_it)->event_handler->OnFrameInfoChanged(
    609         (*client_it)->controller_id,
    610         info.width,
    611         info.height,
    612         info.frame_rate);
    613   }
    614 }
    615 
    616 void VideoCaptureController::DoErrorOnIOThread() {
    617   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    618   state_ = VIDEO_CAPTURE_STATE_ERROR;
    619   ControllerClients::iterator client_it;
    620   for (client_it = controller_clients_.begin();
    621        client_it != controller_clients_.end(); ++client_it) {
    622     (*client_it)->event_handler->OnError((*client_it)->controller_id);
    623   }
    624   for (client_it = pending_clients_.begin();
    625        client_it != pending_clients_.end(); ++client_it) {
    626     (*client_it)->event_handler->OnError((*client_it)->controller_id);
    627   }
    628 }
    629 
    630 void VideoCaptureController::DoDeviceStoppedOnIOThread() {
    631   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    632   device_in_use_ = false;
    633   if (state_ == VIDEO_CAPTURE_STATE_STOPPING) {
    634     PostStopping();
    635   }
    636 }
    637 
    638 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) {
    639   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    640   DCHECK(frame_info_available_);
    641   client->event_handler->OnFrameInfo(client->controller_id,
    642                                      frame_info_);
    643   for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) {
    644     base::SharedMemoryHandle remote_handle =
    645         buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle);
    646 
    647     client->event_handler->OnBufferCreated(client->controller_id,
    648                                            remote_handle,
    649                                            buffer_pool_->GetMemorySize(),
    650                                            buffer_id);
    651   }
    652 }
    653 
    654 VideoCaptureController::ControllerClient*
    655 VideoCaptureController::FindClient(
    656     const VideoCaptureControllerID& id,
    657     VideoCaptureControllerEventHandler* handler,
    658     const ControllerClients& clients) {
    659   for (ControllerClients::const_iterator client_it = clients.begin();
    660        client_it != clients.end(); ++client_it) {
    661     if ((*client_it)->controller_id == id &&
    662         (*client_it)->event_handler == handler) {
    663       return *client_it;
    664     }
    665   }
    666   return NULL;
    667 }
    668 
    669 VideoCaptureController::ControllerClient*
    670 VideoCaptureController::FindClient(
    671     int session_id,
    672     const ControllerClients& clients) {
    673   for (ControllerClients::const_iterator client_it = clients.begin();
    674        client_it != clients.end(); ++client_it) {
    675     if ((*client_it)->parameters.session_id == session_id) {
    676       return *client_it;
    677     }
    678   }
    679   return NULL;
    680 }
    681 
    682 // This function is called when all buffers have been returned to controller,
    683 // or when device is stopped. It decides whether the device needs to be
    684 // restarted.
    685 void VideoCaptureController::PostStopping() {
    686   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    687   DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING);
    688 
    689   // When clients still have some buffers, or device has not been stopped yet,
    690   // do nothing.
    691   if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) ||
    692       device_in_use_)
    693     return;
    694 
    695   {
    696     base::AutoLock lock(buffer_pool_lock_);
    697     buffer_pool_ = NULL;
    698   }
    699 
    700   // No more client. Therefore the controller is stopped.
    701   if (controller_clients_.empty() && pending_clients_.empty()) {
    702     state_ = VIDEO_CAPTURE_STATE_STOPPED;
    703     return;
    704   }
    705 
    706   // Restart the device.
    707   current_params_.width = 0;
    708   current_params_.height = 0;
    709   ControllerClients::iterator client_it;
    710   for (client_it = controller_clients_.begin();
    711        client_it != controller_clients_.end(); ++client_it) {
    712     if (current_params_.width < (*client_it)->parameters.width)
    713       current_params_.width = (*client_it)->parameters.width;
    714     if (current_params_.height < (*client_it)->parameters.height)
    715       current_params_.height = (*client_it)->parameters.height;
    716   }
    717   for (client_it = pending_clients_.begin();
    718        client_it != pending_clients_.end(); ) {
    719     if (current_params_.width < (*client_it)->parameters.width)
    720       current_params_.width = (*client_it)->parameters.width;
    721     if (current_params_.height < (*client_it)->parameters.height)
    722       current_params_.height = (*client_it)->parameters.height;
    723     controller_clients_.push_back((*client_it));
    724     pending_clients_.erase(client_it++);
    725   }
    726   // Request the manager to start the actual capture.
    727   video_capture_manager_->Start(current_params_, this);
    728   state_ = VIDEO_CAPTURE_STATE_STARTED;
    729   device_in_use_ = true;
    730 }
    731 
    732 }  // namespace content
    733