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