• 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/videoprocessor.h"
34 #include "talk/media/base/videorenderer.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() { return adapter_.get(); }
GetVideoCapturer()54   VideoCapturer* GetVideoCapturer() { return adapter()->video_capturer(); }
55 
start_count() const56   int start_count() const { return start_count_; }
57 
58  private:
59   struct CaptureResolutionInfo {
60     VideoFormat video_format;
61     int format_ref_count;
62   };
63   typedef std::vector<CaptureResolutionInfo> CaptureFormats;
64 
65   explicit VideoCapturerState(CaptureRenderAdapter* adapter);
66 
67   rtc::scoped_ptr<CaptureRenderAdapter> adapter_;
68 
69   int start_count_;
70   CaptureFormats capture_formats_;
71 };
72 
73 const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
74   640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
75 };
76 
VideoCapturerState(CaptureRenderAdapter * adapter)77 VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
78     : adapter_(adapter), start_count_(1) {}
79 
Create(VideoCapturer * video_capturer)80 VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) {
81   CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer);
82   if (!adapter) {
83     return NULL;
84   }
85   return new VideoCapturerState(adapter);
86 }
87 
AddCaptureResolution(const VideoFormat & desired_format)88 void VideoCapturerState::AddCaptureResolution(
89     const VideoFormat& desired_format) {
90   for (CaptureFormats::iterator iter = capture_formats_.begin();
91        iter != capture_formats_.end(); ++iter) {
92     if (desired_format == iter->video_format) {
93       ++(iter->format_ref_count);
94       return;
95     }
96   }
97   CaptureResolutionInfo capture_resolution = { desired_format, 1 };
98   capture_formats_.push_back(capture_resolution);
99 }
100 
RemoveCaptureResolution(const VideoFormat & format)101 bool VideoCapturerState::RemoveCaptureResolution(const VideoFormat& format) {
102   for (CaptureFormats::iterator iter = capture_formats_.begin();
103        iter != capture_formats_.end(); ++iter) {
104     if (format == iter->video_format) {
105       --(iter->format_ref_count);
106       if (iter->format_ref_count == 0) {
107         capture_formats_.erase(iter);
108       }
109       return true;
110     }
111   }
112   return false;
113 }
114 
GetHighestFormat(VideoCapturer * video_capturer) const115 VideoFormat VideoCapturerState::GetHighestFormat(
116     VideoCapturer* video_capturer) const {
117   VideoFormat highest_format(0, 0, VideoFormat::FpsToInterval(1), FOURCC_ANY);
118   if (capture_formats_.empty()) {
119     VideoFormat default_format(kDefaultCaptureFormat);
120     return default_format;
121   }
122   for (CaptureFormats::const_iterator iter = capture_formats_.begin();
123        iter != capture_formats_.end(); ++iter) {
124     if (iter->video_format.width > highest_format.width) {
125       highest_format.width = iter->video_format.width;
126     }
127     if (iter->video_format.height > highest_format.height) {
128       highest_format.height = iter->video_format.height;
129     }
130     if (iter->video_format.interval < highest_format.interval) {
131       highest_format.interval = iter->video_format.interval;
132     }
133   }
134   return highest_format;
135 }
136 
IncCaptureStartRef()137 int VideoCapturerState::IncCaptureStartRef() { return ++start_count_; }
138 
DecCaptureStartRef()139 int VideoCapturerState::DecCaptureStartRef() {
140   if (start_count_ > 0) {
141     // Start count may be 0 if a capturer was added but never started.
142     --start_count_;
143   }
144   return start_count_;
145 }
146 
~CaptureManager()147 CaptureManager::~CaptureManager() {
148   // Since we don't own any of the capturers, all capturers should have been
149   // cleaned up before we get here. In fact, in the normal shutdown sequence,
150   // all capturers *will* be shut down by now, so trying to stop them here
151   // will crash. If we're still tracking any, it's a dangling pointer.
152   if (!capture_states_.empty()) {
153     ASSERT(false &&
154            "CaptureManager destructing while still tracking capturers!");
155     // Delete remaining VideoCapturerStates, but don't touch the capturers.
156     do {
157       CaptureStates::iterator it = capture_states_.begin();
158       delete it->second;
159       capture_states_.erase(it);
160     } while (!capture_states_.empty());
161   }
162 }
163 
StartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & desired_format)164 bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
165                                        const VideoFormat& desired_format) {
166   if (desired_format.width == 0 || desired_format.height == 0) {
167     return false;
168   }
169   if (!video_capturer) {
170     return false;
171   }
172   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
173   if (capture_state) {
174     const int ref_count = capture_state->IncCaptureStartRef();
175     if (ref_count < 1) {
176       ASSERT(false);
177     }
178     // VideoCapturer has already been started. Don't start listening to
179     // callbacks since that has already been done.
180     capture_state->AddCaptureResolution(desired_format);
181     return true;
182   }
183   if (!RegisterVideoCapturer(video_capturer)) {
184     return false;
185   }
186   capture_state = GetCaptureState(video_capturer);
187   ASSERT(capture_state != NULL);
188   capture_state->AddCaptureResolution(desired_format);
189   if (!StartWithBestCaptureFormat(capture_state, video_capturer)) {
190     UnregisterVideoCapturer(capture_state);
191     return false;
192   }
193   return true;
194 }
195 
StopVideoCapture(VideoCapturer * video_capturer,const VideoFormat & format)196 bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
197                                       const VideoFormat& format) {
198   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
199   if (!capture_state) {
200     return false;
201   }
202   if (!capture_state->RemoveCaptureResolution(format)) {
203     return false;
204   }
205 
206   if (capture_state->DecCaptureStartRef() == 0) {
207     // Unregistering cannot fail as capture_state is not NULL.
208     UnregisterVideoCapturer(capture_state);
209   }
210   return true;
211 }
212 
RestartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & previous_format,const VideoFormat & desired_format,CaptureManager::RestartOptions options)213 bool CaptureManager::RestartVideoCapture(
214     VideoCapturer* video_capturer,
215     const VideoFormat& previous_format,
216     const VideoFormat& desired_format,
217     CaptureManager::RestartOptions options) {
218   if (!IsCapturerRegistered(video_capturer)) {
219     LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
220     return false;
221   }
222   // Start the new format first. This keeps the capturer running.
223   if (!StartVideoCapture(video_capturer, desired_format)) {
224     LOG(LS_ERROR) << "RestartVideoCapture: unable to start video capture with "
225         "desired_format=" << desired_format.ToString();
226     return false;
227   }
228   // Stop the old format.
229   if (!StopVideoCapture(video_capturer, previous_format)) {
230     LOG(LS_ERROR) << "RestartVideoCapture: unable to stop video capture with "
231         "previous_format=" << previous_format.ToString();
232     // Undo the start request we just performed.
233     StopVideoCapture(video_capturer, desired_format);
234     return false;
235   }
236 
237   switch (options) {
238     case kForceRestart: {
239       VideoCapturerState* capture_state = GetCaptureState(video_capturer);
240       ASSERT(capture_state && capture_state->start_count() > 0);
241       // Try a restart using the new best resolution.
242       VideoFormat highest_asked_format =
243           capture_state->GetHighestFormat(video_capturer);
244       VideoFormat capture_format;
245       if (video_capturer->GetBestCaptureFormat(highest_asked_format,
246                                                &capture_format)) {
247         if (!video_capturer->Restart(capture_format)) {
248           LOG(LS_ERROR) << "RestartVideoCapture: Restart failed.";
249         }
250       } else {
251         LOG(LS_WARNING)
252             << "RestartVideoCapture: Couldn't find a best capture format for "
253             << highest_asked_format.ToString();
254       }
255       break;
256     }
257     case kRequestRestart:
258       // TODO(ryanpetrie): Support restart requests. Should this
259       // to-be-implemented logic be used for {Start,Stop}VideoCapture as well?
260       break;
261     default:
262       LOG(LS_ERROR) << "Unknown/unimplemented RestartOption";
263       break;
264   }
265   return true;
266 }
267 
AddVideoRenderer(VideoCapturer * video_capturer,VideoRenderer * video_renderer)268 bool CaptureManager::AddVideoRenderer(VideoCapturer* video_capturer,
269                                       VideoRenderer* video_renderer) {
270   if (!video_capturer || !video_renderer) {
271     return false;
272   }
273   CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
274   if (!adapter) {
275     return false;
276   }
277   return adapter->AddRenderer(video_renderer);
278 }
279 
RemoveVideoRenderer(VideoCapturer * video_capturer,VideoRenderer * video_renderer)280 bool CaptureManager::RemoveVideoRenderer(VideoCapturer* video_capturer,
281                                          VideoRenderer* video_renderer) {
282   if (!video_capturer || !video_renderer) {
283     return false;
284   }
285   CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
286   if (!adapter) {
287     return false;
288   }
289   return adapter->RemoveRenderer(video_renderer);
290 }
291 
AddVideoProcessor(VideoCapturer * video_capturer,VideoProcessor * video_processor)292 bool CaptureManager::AddVideoProcessor(VideoCapturer* video_capturer,
293                                        VideoProcessor* video_processor) {
294   if (!video_capturer || !video_processor) {
295     return false;
296   }
297   if (!IsCapturerRegistered(video_capturer)) {
298     return false;
299   }
300   video_capturer->AddVideoProcessor(video_processor);
301   return true;
302 }
303 
RemoveVideoProcessor(VideoCapturer * video_capturer,VideoProcessor * video_processor)304 bool CaptureManager::RemoveVideoProcessor(VideoCapturer* video_capturer,
305                                           VideoProcessor* video_processor) {
306   if (!video_capturer || !video_processor) {
307     return false;
308   }
309   if (!IsCapturerRegistered(video_capturer)) {
310     return false;
311   }
312   return video_capturer->RemoveVideoProcessor(video_processor);
313 }
314 
IsCapturerRegistered(VideoCapturer * video_capturer) const315 bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
316   return GetCaptureState(video_capturer) != NULL;
317 }
318 
RegisterVideoCapturer(VideoCapturer * video_capturer)319 bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
320   VideoCapturerState* capture_state =
321       VideoCapturerState::Create(video_capturer);
322   if (!capture_state) {
323     return false;
324   }
325   capture_states_[video_capturer] = capture_state;
326   SignalCapturerStateChange.repeat(video_capturer->SignalStateChange);
327   return true;
328 }
329 
UnregisterVideoCapturer(VideoCapturerState * capture_state)330 void CaptureManager::UnregisterVideoCapturer(
331     VideoCapturerState* capture_state) {
332   VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
333   capture_states_.erase(video_capturer);
334   delete capture_state;
335 
336   // When unregistering a VideoCapturer, the CaptureManager needs to unregister
337   // from all state change callbacks from the VideoCapturer. E.g. to avoid
338   // problems with multiple callbacks if registering the same VideoCapturer
339   // multiple times. The VideoCapturer will update the capturer state. However,
340   // this is done through Post-calls which means it may happen at any time. If
341   // the CaptureManager no longer is listening to the VideoCapturer it will not
342   // receive those callbacks. Here it is made sure that the the callback is
343   // indeed sent by letting the ChannelManager do the signaling. The downside is
344   // that the callback may happen before the VideoCapturer is stopped. However,
345   // for the CaptureManager it doesn't matter as it will no longer receive any
346   // frames from the VideoCapturer.
347   SignalCapturerStateChange.stop(video_capturer->SignalStateChange);
348   video_capturer->Stop();
349   SignalCapturerStateChange(video_capturer, CS_STOPPED);
350 }
351 
StartWithBestCaptureFormat(VideoCapturerState * capture_state,VideoCapturer * video_capturer)352 bool CaptureManager::StartWithBestCaptureFormat(
353     VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
354   VideoFormat highest_asked_format =
355       capture_state->GetHighestFormat(video_capturer);
356   VideoFormat capture_format;
357   if (!video_capturer->GetBestCaptureFormat(highest_asked_format,
358                                             &capture_format)) {
359     LOG(LS_WARNING) << "Unsupported format:"
360                     << " width=" << highest_asked_format.width
361                     << " height=" << highest_asked_format.height
362                     << ". Supported formats are:";
363     const std::vector<VideoFormat>* formats =
364         video_capturer->GetSupportedFormats();
365     ASSERT(formats != NULL);
366     for (std::vector<VideoFormat>::const_iterator i = formats->begin();
367          i != formats->end(); ++i) {
368       const VideoFormat& format = *i;
369       LOG(LS_WARNING) << "  " << GetFourccName(format.fourcc)
370                       << ":" << format.width << "x" << format.height << "x"
371                       << format.framerate();
372     }
373     return false;
374   }
375   return video_capturer->StartCapturing(capture_format);
376 }
377 
GetCaptureState(VideoCapturer * video_capturer) const378 VideoCapturerState* CaptureManager::GetCaptureState(
379     VideoCapturer* video_capturer) const {
380   CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
381   if (iter == capture_states_.end()) {
382     return NULL;
383   }
384   return iter->second;
385 }
386 
GetAdapter(VideoCapturer * video_capturer) const387 CaptureRenderAdapter* CaptureManager::GetAdapter(
388     VideoCapturer* video_capturer) const {
389   VideoCapturerState* capture_state = GetCaptureState(video_capturer);
390   if (!capture_state) {
391     return NULL;
392   }
393   return capture_state->adapter();
394 }
395 
396 }  // namespace cricket
397