• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
~VideoCapturerState()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();
adapter()53   CaptureRenderAdapter* adapter() {
54     RTC_DCHECK(thread_checker_.CalledOnValidThread());
55     return adapter_.get();
56   }
GetVideoCapturer()57   VideoCapturer* GetVideoCapturer() {
58     RTC_DCHECK(thread_checker_.CalledOnValidThread());
59     return adapter()->video_capturer();
60   }
61 
start_count() const62   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 
VideoCapturerState(CaptureRenderAdapter * adapter)87 VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
88     : adapter_(adapter), start_count_(1) {}
89 
90 // static
Create(VideoCapturer * video_capturer)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 
AddCaptureResolution(const VideoFormat & desired_format)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 
RemoveCaptureResolution(const VideoFormat & format)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 
GetHighestFormat(VideoCapturer * video_capturer) const128 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 
IncCaptureStartRef()151 int VideoCapturerState::IncCaptureStartRef() {
152   RTC_DCHECK(thread_checker_.CalledOnValidThread());
153   return ++start_count_;
154 }
155 
DecCaptureStartRef()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 
CaptureManager()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 
~CaptureManager()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 
StartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & desired_format)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 
StopVideoCapture(VideoCapturer * video_capturer,const VideoFormat & format)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 
RestartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & previous_format,const VideoFormat & desired_format,CaptureManager::RestartOptions options)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 
AddVideoRenderer(VideoCapturer * video_capturer,VideoRenderer * video_renderer)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 
RemoveVideoRenderer(VideoCapturer * video_capturer,VideoRenderer * video_renderer)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 
IsCapturerRegistered(VideoCapturer * video_capturer) const316 bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
317   RTC_DCHECK(thread_checker_.CalledOnValidThread());
318   return GetCaptureState(video_capturer) != NULL;
319 }
320 
RegisterVideoCapturer(VideoCapturer * video_capturer)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 
UnregisterVideoCapturer(VideoCapturerState * capture_state)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 
StartWithBestCaptureFormat(VideoCapturerState * capture_state,VideoCapturer * video_capturer)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 
GetCaptureState(VideoCapturer * video_capturer) const385 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 
GetAdapter(VideoCapturer * video_capturer) const395 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