Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/media/base/capturemanager.h"
     29 
     30 #include <algorithm>
     31 
     32 #include "talk/media/base/videocapturer.h"
     33 #include "talk/media/base/videorenderer.h"
     34 #include "webrtc/base/checks.h"
     35 #include "webrtc/base/logging.h"
     36 
     37 namespace cricket {
     38 
     39 // CaptureManager helper class.
     40 class VideoCapturerState {
     41  public:
     42   static const VideoFormatPod kDefaultCaptureFormat;
     43 
     44   static VideoCapturerState* Create(VideoCapturer* video_capturer);
     45   ~VideoCapturerState() {}
     46 
     47   void AddCaptureResolution(const VideoFormat& desired_format);
     48   bool RemoveCaptureResolution(const VideoFormat& format);
     49   VideoFormat GetHighestFormat(VideoCapturer* video_capturer) const;
     50 
     51   int IncCaptureStartRef();
     52   int DecCaptureStartRef();
     53   CaptureRenderAdapter* adapter() {
     54     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     55     return adapter_.get();
     56   }
     57   VideoCapturer* GetVideoCapturer() {
     58     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     59     return adapter()->video_capturer();
     60   }
     61 
     62   int start_count() const {
     63     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     64     return start_count_;
     65   }
     66 
     67  private:
     68   struct CaptureResolutionInfo {
     69     VideoFormat video_format;
     70     int format_ref_count;
     71   };
     72   typedef std::vector<CaptureResolutionInfo> CaptureFormats;
     73 
     74   explicit VideoCapturerState(CaptureRenderAdapter* adapter);
     75 
     76   rtc::ThreadChecker thread_checker_;
     77   rtc::scoped_ptr<CaptureRenderAdapter> adapter_;
     78 
     79   int start_count_;
     80   CaptureFormats capture_formats_;
     81 };
     82 
     83 const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
     84   640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
     85 };
     86 
     87 VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
     88     : adapter_(adapter), start_count_(1) {}
     89 
     90 // static
     91 VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) {
     92   CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer);
     93   if (!adapter) {
     94     return NULL;
     95   }
     96   return new VideoCapturerState(adapter);
     97 }
     98 
     99 void VideoCapturerState::AddCaptureResolution(
    100     const VideoFormat& desired_format) {
    101   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    102   for (CaptureFormats::iterator iter = capture_formats_.begin();
    103        iter != capture_formats_.end(); ++iter) {
    104     if (desired_format == iter->video_format) {
    105       ++(iter->format_ref_count);
    106       return;
    107     }
    108   }
    109   CaptureResolutionInfo capture_resolution = { desired_format, 1 };
    110   capture_formats_.push_back(capture_resolution);
    111 }
    112 
    113 bool VideoCapturerState::RemoveCaptureResolution(const VideoFormat& format) {
    114   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    115   for (CaptureFormats::iterator iter = capture_formats_.begin();
    116        iter != capture_formats_.end(); ++iter) {
    117     if (format == iter->video_format) {
    118       --(iter->format_ref_count);
    119       if (iter->format_ref_count == 0) {
    120         capture_formats_.erase(iter);
    121       }
    122       return true;
    123     }
    124   }
    125   return false;
    126 }
    127 
    128 VideoFormat VideoCapturerState::GetHighestFormat(
    129     VideoCapturer* video_capturer) const {
    130   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    131   VideoFormat highest_format(0, 0, VideoFormat::FpsToInterval(1), FOURCC_ANY);
    132   if (capture_formats_.empty()) {
    133     VideoFormat default_format(kDefaultCaptureFormat);
    134     return default_format;
    135   }
    136   for (CaptureFormats::const_iterator iter = capture_formats_.begin();
    137        iter != capture_formats_.end(); ++iter) {
    138     if (iter->video_format.width > highest_format.width) {
    139       highest_format.width = iter->video_format.width;
    140     }
    141     if (iter->video_format.height > highest_format.height) {
    142       highest_format.height = iter->video_format.height;
    143     }
    144     if (iter->video_format.interval < highest_format.interval) {
    145       highest_format.interval = iter->video_format.interval;
    146     }
    147   }
    148   return highest_format;
    149 }
    150 
    151 int VideoCapturerState::IncCaptureStartRef() {
    152   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    153   return ++start_count_;
    154 }
    155 
    156 int VideoCapturerState::DecCaptureStartRef() {
    157   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    158   if (start_count_ > 0) {
    159     // Start count may be 0 if a capturer was added but never started.
    160     --start_count_;
    161   }
    162   return start_count_;
    163 }
    164 
    165 CaptureManager::CaptureManager() {
    166   // Allowing construction of manager in any thread as long as subsequent calls
    167   // are all from the same thread.
    168   thread_checker_.DetachFromThread();
    169 }
    170 
    171 CaptureManager::~CaptureManager() {
    172   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    173 
    174   // Since we don't own any of the capturers, all capturers should have been
    175   // cleaned up before we get here. In fact, in the normal shutdown sequence,
    176   // all capturers *will* be shut down by now, so trying to stop them here
    177   // will crash. If we're still tracking any, it's a dangling pointer.
    178   // TODO(hbos): RTC_DCHECK instead of RTC_CHECK until we figure out why
    179   // capture_states_ is not always empty here.
    180   RTC_DCHECK(capture_states_.empty());
    181 }
    182 
    183 bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
    184                                        const VideoFormat& desired_format) {
    185   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    186   if (desired_format.width == 0 || desired_format.height == 0) {
    187     return false;
    188   }
    189   if (!video_capturer) {
    190     return false;
    191   }
    192   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
    193   if (capture_state) {
    194     const int ref_count = capture_state->IncCaptureStartRef();
    195     if (ref_count < 1) {
    196       ASSERT(false);
    197     }
    198     // VideoCapturer has already been started. Don't start listening to
    199     // callbacks since that has already been done.
    200     capture_state->AddCaptureResolution(desired_format);
    201     return true;
    202   }
    203   if (!RegisterVideoCapturer(video_capturer)) {
    204     return false;
    205   }
    206   capture_state = GetCaptureState(video_capturer);
    207   ASSERT(capture_state != NULL);
    208   capture_state->AddCaptureResolution(desired_format);
    209   if (!StartWithBestCaptureFormat(capture_state, video_capturer)) {
    210     UnregisterVideoCapturer(capture_state);
    211     return false;
    212   }
    213   return true;
    214 }
    215 
    216 bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
    217                                       const VideoFormat& format) {
    218   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    219   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
    220   if (!capture_state) {
    221     return false;
    222   }
    223   if (!capture_state->RemoveCaptureResolution(format)) {
    224     return false;
    225   }
    226 
    227   if (capture_state->DecCaptureStartRef() == 0) {
    228     // Unregistering cannot fail as capture_state is not NULL.
    229     UnregisterVideoCapturer(capture_state);
    230   }
    231   return true;
    232 }
    233 
    234 bool CaptureManager::RestartVideoCapture(
    235     VideoCapturer* video_capturer,
    236     const VideoFormat& previous_format,
    237     const VideoFormat& desired_format,
    238     CaptureManager::RestartOptions options) {
    239   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    240   if (!IsCapturerRegistered(video_capturer)) {
    241     LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
    242     return false;
    243   }
    244   // Start the new format first. This keeps the capturer running.
    245   if (!StartVideoCapture(video_capturer, desired_format)) {
    246     LOG(LS_ERROR) << "RestartVideoCapture: unable to start video capture with "
    247         "desired_format=" << desired_format.ToString();
    248     return false;
    249   }
    250   // Stop the old format.
    251   if (!StopVideoCapture(video_capturer, previous_format)) {
    252     LOG(LS_ERROR) << "RestartVideoCapture: unable to stop video capture with "
    253         "previous_format=" << previous_format.ToString();
    254     // Undo the start request we just performed.
    255     StopVideoCapture(video_capturer, desired_format);
    256     return false;
    257   }
    258 
    259   switch (options) {
    260     case kForceRestart: {
    261       VideoCapturerState* capture_state = GetCaptureState(video_capturer);
    262       ASSERT(capture_state && capture_state->start_count() > 0);
    263       // Try a restart using the new best resolution.
    264       VideoFormat highest_asked_format =
    265           capture_state->GetHighestFormat(video_capturer);
    266       VideoFormat capture_format;
    267       if (video_capturer->GetBestCaptureFormat(highest_asked_format,
    268                                                &capture_format)) {
    269         if (!video_capturer->Restart(capture_format)) {
    270           LOG(LS_ERROR) << "RestartVideoCapture: Restart failed.";
    271         }
    272       } else {
    273         LOG(LS_WARNING)
    274             << "RestartVideoCapture: Couldn't find a best capture format for "
    275             << highest_asked_format.ToString();
    276       }
    277       break;
    278     }
    279     case kRequestRestart:
    280       // TODO(ryanpetrie): Support restart requests. Should this
    281       // to-be-implemented logic be used for {Start,Stop}VideoCapture as well?
    282       break;
    283     default:
    284       LOG(LS_ERROR) << "Unknown/unimplemented RestartOption";
    285       break;
    286   }
    287   return true;
    288 }
    289 
    290 bool CaptureManager::AddVideoRenderer(VideoCapturer* video_capturer,
    291                                       VideoRenderer* video_renderer) {
    292   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    293   if (!video_capturer || !video_renderer) {
    294     return false;
    295   }
    296   CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
    297   if (!adapter) {
    298     return false;
    299   }
    300   return adapter->AddRenderer(video_renderer);
    301 }
    302 
    303 bool CaptureManager::RemoveVideoRenderer(VideoCapturer* video_capturer,
    304                                          VideoRenderer* video_renderer) {
    305   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    306   if (!video_capturer || !video_renderer) {
    307     return false;
    308   }
    309   CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
    310   if (!adapter) {
    311     return false;
    312   }
    313   return adapter->RemoveRenderer(video_renderer);
    314 }
    315 
    316 bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
    317   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    318   return GetCaptureState(video_capturer) != NULL;
    319 }
    320 
    321 bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
    322   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    323   VideoCapturerState* capture_state =
    324       VideoCapturerState::Create(video_capturer);
    325   if (!capture_state) {
    326     return false;
    327   }
    328   capture_states_[video_capturer] = capture_state;
    329   SignalCapturerStateChange.repeat(video_capturer->SignalStateChange);
    330   return true;
    331 }
    332 
    333 void CaptureManager::UnregisterVideoCapturer(
    334     VideoCapturerState* capture_state) {
    335   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    336   VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
    337   capture_states_.erase(video_capturer);
    338   delete capture_state;
    339 
    340   // When unregistering a VideoCapturer, the CaptureManager needs to unregister
    341   // from all state change callbacks from the VideoCapturer. E.g. to avoid
    342   // problems with multiple callbacks if registering the same VideoCapturer
    343   // multiple times. The VideoCapturer will update the capturer state. However,
    344   // this is done through Post-calls which means it may happen at any time. If
    345   // the CaptureManager no longer is listening to the VideoCapturer it will not
    346   // receive those callbacks. Here it is made sure that the the callback is
    347   // indeed sent by letting the ChannelManager do the signaling. The downside is
    348   // that the callback may happen before the VideoCapturer is stopped. However,
    349   // for the CaptureManager it doesn't matter as it will no longer receive any
    350   // frames from the VideoCapturer.
    351   SignalCapturerStateChange.stop(video_capturer->SignalStateChange);
    352   if (video_capturer->IsRunning()) {
    353     video_capturer->Stop();
    354     SignalCapturerStateChange(video_capturer, CS_STOPPED);
    355   }
    356 }
    357 
    358 bool CaptureManager::StartWithBestCaptureFormat(
    359     VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
    360   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    361   VideoFormat highest_asked_format =
    362       capture_state->GetHighestFormat(video_capturer);
    363   VideoFormat capture_format;
    364   if (!video_capturer->GetBestCaptureFormat(highest_asked_format,
    365                                             &capture_format)) {
    366     LOG(LS_WARNING) << "Unsupported format:"
    367                     << " width=" << highest_asked_format.width
    368                     << " height=" << highest_asked_format.height
    369                     << ". Supported formats are:";
    370     const std::vector<VideoFormat>* formats =
    371         video_capturer->GetSupportedFormats();
    372     ASSERT(formats != NULL);
    373     for (std::vector<VideoFormat>::const_iterator i = formats->begin();
    374          i != formats->end(); ++i) {
    375       const VideoFormat& format = *i;
    376       LOG(LS_WARNING) << "  " << GetFourccName(format.fourcc)
    377                       << ":" << format.width << "x" << format.height << "x"
    378                       << format.framerate();
    379     }
    380     return false;
    381   }
    382   return video_capturer->StartCapturing(capture_format);
    383 }
    384 
    385 VideoCapturerState* CaptureManager::GetCaptureState(
    386     VideoCapturer* video_capturer) const {
    387   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    388   CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
    389   if (iter == capture_states_.end()) {
    390     return NULL;
    391   }
    392   return iter->second;
    393 }
    394 
    395 CaptureRenderAdapter* CaptureManager::GetAdapter(
    396     VideoCapturer* video_capturer) const {
    397   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    398   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
    399   if (!capture_state) {
    400     return NULL;
    401   }
    402   return capture_state->adapter();
    403 }
    404 
    405 }  // namespace cricket
    406