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 // Implementation notes about interactions with VideoCaptureImpl.
      6 //
      7 // How is VideoCaptureImpl used:
      8 //
      9 // VideoCaptureImpl is an IO thread object while VideoCaptureImplManager
     10 // lives only on the render thread. It is only possible to access an
     11 // object of VideoCaptureImpl via a task on the IO thread.
     12 //
     13 // How is VideoCaptureImpl deleted:
     14 //
     15 // A task is posted to the IO thread to delete a VideoCaptureImpl.
     16 // Immediately after that the pointer to it is dropped. This means no
     17 // access to this VideoCaptureImpl object is possible on the render
     18 // thread. Also note that VideoCaptureImpl does not post task to itself.
     19 //
     20 // The use of Unretained:
     21 //
     22 // We make sure deletion is the last task on the IO thread for a
     23 // VideoCaptureImpl object. This allows the use of Unretained() binding.
     24 
     25 #include "content/renderer/media/video_capture_impl_manager.h"
     26 
     27 #include "base/bind.h"
     28 #include "base/bind_helpers.h"
     29 #include "content/child/child_process.h"
     30 #include "content/renderer/media/video_capture_impl.h"
     31 #include "content/renderer/media/video_capture_message_filter.h"
     32 #include "media/base/bind_to_current_loop.h"
     33 
     34 namespace content {
     35 
     36 VideoCaptureImplManager::VideoCaptureImplManager()
     37     : next_client_id_(0),
     38       filter_(new VideoCaptureMessageFilter()),
     39       weak_factory_(this) {
     40 }
     41 
     42 VideoCaptureImplManager::~VideoCaptureImplManager() {
     43   DCHECK(thread_checker_.CalledOnValidThread());
     44   if (devices_.empty())
     45     return;
     46   // Forcibly release all video capture resources.
     47   for (VideoCaptureDeviceMap::iterator it = devices_.begin();
     48        it != devices_.end(); ++it) {
     49     VideoCaptureImpl* impl = it->second.second;
     50     ChildProcess::current()->io_message_loop_proxy()->PostTask(
     51         FROM_HERE,
     52         base::Bind(&VideoCaptureImpl::DeInit,
     53                    base::Unretained(impl)));
     54     ChildProcess::current()->io_message_loop_proxy()->PostTask(
     55         FROM_HERE,
     56         base::Bind(&base::DeletePointer<VideoCaptureImpl>,
     57                    base::Unretained(impl)));
     58   }
     59   devices_.clear();
     60 }
     61 
     62 base::Closure VideoCaptureImplManager::UseDevice(
     63     media::VideoCaptureSessionId id) {
     64   DCHECK(thread_checker_.CalledOnValidThread());
     65 
     66   VideoCaptureImpl* impl = NULL;
     67   VideoCaptureDeviceMap::iterator it = devices_.find(id);
     68   if (it == devices_.end()) {
     69     impl = CreateVideoCaptureImplForTesting(id, filter_.get());
     70     if (!impl)
     71       impl = new VideoCaptureImpl(id, filter_.get());
     72     devices_[id] = std::make_pair(1, impl);
     73     ChildProcess::current()->io_message_loop_proxy()->PostTask(
     74         FROM_HERE,
     75         base::Bind(&VideoCaptureImpl::Init,
     76                    base::Unretained(impl)));
     77   } else {
     78     ++it->second.first;
     79   }
     80   return base::Bind(&VideoCaptureImplManager::UnrefDevice,
     81                     weak_factory_.GetWeakPtr(), id);
     82 }
     83 
     84 base::Closure VideoCaptureImplManager::StartCapture(
     85     media::VideoCaptureSessionId id,
     86     const media::VideoCaptureParams& params,
     87     const VideoCaptureStateUpdateCB& state_update_cb,
     88     const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
     89   DCHECK(thread_checker_.CalledOnValidThread());
     90   VideoCaptureDeviceMap::iterator it = devices_.find(id);
     91   DCHECK(it != devices_.end());
     92   VideoCaptureImpl* impl = it->second.second;
     93 
     94   // This ID is used to identify a client of VideoCaptureImpl.
     95   const int client_id = ++next_client_id_;
     96 
     97   ChildProcess::current()->io_message_loop_proxy()->PostTask(
     98       FROM_HERE,
     99       base::Bind(&VideoCaptureImpl::StartCapture,
    100                  base::Unretained(impl),
    101                  client_id,
    102                  params,
    103                  state_update_cb,
    104                  deliver_frame_cb));
    105   return base::Bind(&VideoCaptureImplManager::StopCapture,
    106                     weak_factory_.GetWeakPtr(),
    107                     client_id, id);
    108 }
    109 
    110 void VideoCaptureImplManager::GetDeviceSupportedFormats(
    111     media::VideoCaptureSessionId id,
    112     const VideoCaptureDeviceFormatsCB& callback) {
    113   DCHECK(thread_checker_.CalledOnValidThread());
    114   VideoCaptureDeviceMap::iterator it = devices_.find(id);
    115   DCHECK(it != devices_.end());
    116   VideoCaptureImpl* impl = it->second.second;
    117   ChildProcess::current()->io_message_loop_proxy()->PostTask(
    118       FROM_HERE,
    119       base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
    120                  base::Unretained(impl), callback));
    121 }
    122 
    123 void VideoCaptureImplManager::GetDeviceFormatsInUse(
    124     media::VideoCaptureSessionId id,
    125     const VideoCaptureDeviceFormatsCB& callback) {
    126   DCHECK(thread_checker_.CalledOnValidThread());
    127   VideoCaptureDeviceMap::iterator it = devices_.find(id);
    128   DCHECK(it != devices_.end());
    129   VideoCaptureImpl* impl = it->second.second;
    130   ChildProcess::current()->io_message_loop_proxy()->PostTask(
    131       FROM_HERE,
    132       base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
    133                  base::Unretained(impl), callback));
    134 }
    135 
    136 VideoCaptureImpl*
    137 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
    138     media::VideoCaptureSessionId id,
    139     VideoCaptureMessageFilter* filter) const {
    140   return NULL;
    141 }
    142 
    143 void VideoCaptureImplManager::StopCapture(
    144     int client_id, media::VideoCaptureSessionId id) {
    145   DCHECK(thread_checker_.CalledOnValidThread());
    146   VideoCaptureDeviceMap::iterator it = devices_.find(id);
    147   DCHECK(it != devices_.end());
    148   VideoCaptureImpl* impl = it->second.second;
    149   ChildProcess::current()->io_message_loop_proxy()->PostTask(
    150       FROM_HERE,
    151       base::Bind(&VideoCaptureImpl::StopCapture,
    152                  base::Unretained(impl), client_id));
    153 }
    154 
    155 void VideoCaptureImplManager::UnrefDevice(
    156     media::VideoCaptureSessionId id) {
    157   DCHECK(thread_checker_.CalledOnValidThread());
    158   VideoCaptureDeviceMap::iterator it = devices_.find(id);
    159   DCHECK(it != devices_.end());
    160   VideoCaptureImpl* impl = it->second.second;
    161 
    162   // Unref and destroy on the IO thread if there's no more client.
    163   DCHECK(it->second.first);
    164   --it->second.first;
    165   if (!it->second.first) {
    166     devices_.erase(id);
    167     ChildProcess::current()->io_message_loop_proxy()->PostTask(
    168         FROM_HERE,
    169         base::Bind(&VideoCaptureImpl::DeInit,
    170                    base::Unretained(impl)));
    171     ChildProcess::current()->io_message_loop_proxy()->PostTask(
    172         FROM_HERE,
    173         base::Bind(&base::DeletePointer<VideoCaptureImpl>,
    174                    base::Unretained(impl)));
    175   }
    176 }
    177 
    178 void VideoCaptureImplManager::SuspendDevices(bool suspend) {
    179   DCHECK(thread_checker_.CalledOnValidThread());
    180   for (VideoCaptureDeviceMap::iterator it = devices_.begin();
    181        it != devices_.end(); ++it) {
    182     VideoCaptureImpl* impl = it->second.second;
    183     ChildProcess::current()->io_message_loop_proxy()->PostTask(
    184         FROM_HERE,
    185         base::Bind(&VideoCaptureImpl::SuspendCapture,
    186                    base::Unretained(impl), suspend));
    187   }
    188 }
    189 
    190 }  // namespace content
    191