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
37namespace cricket {
38
39// CaptureManager helper class.
40class 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
83const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
84  640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
85};
86
87VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
88    : adapter_(adapter), start_count_(1) {}
89
90// static
91VideoCapturerState* 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
99void 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
113bool 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
128VideoFormat 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
151int VideoCapturerState::IncCaptureStartRef() {
152  RTC_DCHECK(thread_checker_.CalledOnValidThread());
153  return ++start_count_;
154}
155
156int 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
165CaptureManager::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
171CaptureManager::~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
183bool 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
216bool 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
234bool 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
290bool 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
303bool 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
316bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
317  RTC_DCHECK(thread_checker_.CalledOnValidThread());
318  return GetCaptureState(video_capturer) != NULL;
319}
320
321bool 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
333void 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
358bool 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
385VideoCapturerState* 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
395CaptureRenderAdapter* 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