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