blob: 5705bcd66029094ae43ee932a26a576ef97bf810 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
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/base/logging.h"
33#include "talk/media/base/videocapturer.h"
34#include "talk/media/base/videoprocessor.h"
35#include "talk/media/base/videorenderer.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() { return adapter_.get(); }
54 VideoCapturer* GetVideoCapturer() { return adapter()->video_capturer(); }
55
56 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 talk_base::scoped_ptr<CaptureRenderAdapter> adapter_;
68
69 int start_count_;
70 CaptureFormats capture_formats_;
71};
72
73const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
74 640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
75};
76
77VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
78 : adapter_(adapter), start_count_(1) {}
79
80VideoCapturerState* 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
88void 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
101bool 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
115VideoFormat 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
137int VideoCapturerState::IncCaptureStartRef() { return ++start_count_; }
138
139int 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
147CaptureManager::~CaptureManager() {
148 while (!capture_states_.empty()) {
149 // There may have been multiple calls to StartVideoCapture which means that
150 // an equal number of calls to StopVideoCapture must be made. Note that
151 // StopVideoCapture will remove the element from |capture_states_| when a
152 // successfull stop has been made.
153 UnregisterVideoCapturer(capture_states_.begin()->second);
154 }
155}
156
157bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
158 const VideoFormat& desired_format) {
159 if (desired_format.width == 0 || desired_format.height == 0) {
160 return false;
161 }
162 if (!video_capturer) {
163 return false;
164 }
165 VideoCapturerState* capture_state = GetCaptureState(video_capturer);
166 if (capture_state) {
167 const int ref_count = capture_state->IncCaptureStartRef();
168 if (ref_count < 1) {
169 ASSERT(false);
170 }
171 // VideoCapturer has already been started. Don't start listening to
172 // callbacks since that has already been done.
173 capture_state->AddCaptureResolution(desired_format);
174 return true;
175 }
176 if (!RegisterVideoCapturer(video_capturer)) {
177 return false;
178 }
179 capture_state = GetCaptureState(video_capturer);
180 ASSERT(capture_state != NULL);
181 capture_state->AddCaptureResolution(desired_format);
182 if (!StartWithBestCaptureFormat(capture_state, video_capturer)) {
183 UnregisterVideoCapturer(capture_state);
184 return false;
185 }
186 return true;
187}
188
189bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
190 const VideoFormat& format) {
191 VideoCapturerState* capture_state = GetCaptureState(video_capturer);
192 if (!capture_state) {
193 return false;
194 }
195 if (!capture_state->RemoveCaptureResolution(format)) {
196 return false;
197 }
198
199 if (capture_state->DecCaptureStartRef() == 0) {
200 // Unregistering cannot fail as capture_state is not NULL.
201 UnregisterVideoCapturer(capture_state);
202 }
203 return true;
204}
205
206bool CaptureManager::RestartVideoCapture(
207 VideoCapturer* video_capturer,
208 const VideoFormat& previous_format,
209 const VideoFormat& desired_format,
210 CaptureManager::RestartOptions options) {
211 if (!IsCapturerRegistered(video_capturer)) {
212 LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
213 return false;
214 }
215 // Start the new format first. This keeps the capturer running.
216 if (!StartVideoCapture(video_capturer, desired_format)) {
217 LOG(LS_ERROR) << "RestartVideoCapture: unable to start video capture with "
218 "desired_format=" << desired_format.ToString();
219 return false;
220 }
221 // Stop the old format.
222 if (!StopVideoCapture(video_capturer, previous_format)) {
223 LOG(LS_ERROR) << "RestartVideoCapture: unable to stop video capture with "
224 "previous_format=" << previous_format.ToString();
225 // Undo the start request we just performed.
226 StopVideoCapture(video_capturer, desired_format);
227 return false;
228 }
229
230 switch (options) {
231 case kForceRestart: {
232 VideoCapturerState* capture_state = GetCaptureState(video_capturer);
233 ASSERT(capture_state && capture_state->start_count() > 0);
234 // Try a restart using the new best resolution.
235 VideoFormat highest_asked_format =
236 capture_state->GetHighestFormat(video_capturer);
237 VideoFormat capture_format;
238 if (video_capturer->GetBestCaptureFormat(highest_asked_format,
239 &capture_format)) {
240 if (!video_capturer->Restart(capture_format)) {
241 LOG(LS_ERROR) << "RestartVideoCapture: Restart failed.";
242 }
243 } else {
244 LOG(LS_WARNING)
245 << "RestartVideoCapture: Couldn't find a best capture format for "
246 << highest_asked_format.ToString();
247 }
248 break;
249 }
250 case kRequestRestart:
251 // TODO(ryanpetrie): Support restart requests. Should this
252 // to-be-implemented logic be used for {Start,Stop}VideoCapture as well?
253 break;
254 default:
255 LOG(LS_ERROR) << "Unknown/unimplemented RestartOption";
256 break;
257 }
258 return true;
259}
260
261bool CaptureManager::AddVideoRenderer(VideoCapturer* video_capturer,
262 VideoRenderer* video_renderer) {
263 if (!video_capturer || !video_renderer) {
264 return false;
265 }
266 CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
267 if (!adapter) {
268 return false;
269 }
270 return adapter->AddRenderer(video_renderer);
271}
272
273bool CaptureManager::RemoveVideoRenderer(VideoCapturer* video_capturer,
274 VideoRenderer* video_renderer) {
275 if (!video_capturer || !video_renderer) {
276 return false;
277 }
278 CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
279 if (!adapter) {
280 return false;
281 }
282 return adapter->RemoveRenderer(video_renderer);
283}
284
285bool CaptureManager::AddVideoProcessor(VideoCapturer* video_capturer,
286 VideoProcessor* video_processor) {
287 if (!video_capturer || !video_processor) {
288 return false;
289 }
290 if (!IsCapturerRegistered(video_capturer)) {
291 return false;
292 }
293 video_capturer->AddVideoProcessor(video_processor);
294 return true;
295}
296
297bool CaptureManager::RemoveVideoProcessor(VideoCapturer* video_capturer,
298 VideoProcessor* video_processor) {
299 if (!video_capturer || !video_processor) {
300 return false;
301 }
302 if (!IsCapturerRegistered(video_capturer)) {
303 return false;
304 }
305 return video_capturer->RemoveVideoProcessor(video_processor);
306}
307
308bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
309 return GetCaptureState(video_capturer) != NULL;
310}
311
312bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
313 VideoCapturerState* capture_state =
314 VideoCapturerState::Create(video_capturer);
315 if (!capture_state) {
316 return false;
317 }
318 capture_states_[video_capturer] = capture_state;
319 SignalCapturerStateChange.repeat(video_capturer->SignalStateChange);
320 return true;
321}
322
323void CaptureManager::UnregisterVideoCapturer(
324 VideoCapturerState* capture_state) {
325 VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
326 capture_states_.erase(video_capturer);
327 delete capture_state;
328
329 // When unregistering a VideoCapturer, the CaptureManager needs to unregister
330 // from all state change callbacks from the VideoCapturer. E.g. to avoid
331 // problems with multiple callbacks if registering the same VideoCapturer
332 // multiple times. The VideoCapturer will update the capturer state. However,
333 // this is done through Post-calls which means it may happen at any time. If
334 // the CaptureManager no longer is listening to the VideoCapturer it will not
335 // receive those callbacks. Here it is made sure that the the callback is
336 // indeed sent by letting the ChannelManager do the signaling. The downside is
337 // that the callback may happen before the VideoCapturer is stopped. However,
338 // for the CaptureManager it doesn't matter as it will no longer receive any
339 // frames from the VideoCapturer.
340 SignalCapturerStateChange.stop(video_capturer->SignalStateChange);
341 video_capturer->Stop();
342 SignalCapturerStateChange(video_capturer, CS_STOPPED);
343}
344
345bool CaptureManager::StartWithBestCaptureFormat(
346 VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
347 VideoFormat highest_asked_format =
348 capture_state->GetHighestFormat(video_capturer);
349 VideoFormat capture_format;
350 if (!video_capturer->GetBestCaptureFormat(highest_asked_format,
351 &capture_format)) {
352 LOG(LS_WARNING) << "Unsupported format:"
353 << " width=" << highest_asked_format.width
354 << " height=" << highest_asked_format.height
355 << ". Supported formats are:";
356 const std::vector<VideoFormat>* formats =
357 video_capturer->GetSupportedFormats();
358 ASSERT(formats != NULL);
359 for (std::vector<VideoFormat>::const_iterator i = formats->begin();
360 i != formats->end(); ++i) {
361 const VideoFormat& format = *i;
362 LOG(LS_WARNING) << " " << GetFourccName(format.fourcc)
363 << ":" << format.width << "x" << format.height << "x"
364 << format.framerate();
365 }
366 return false;
367 }
368 return video_capturer->StartCapturing(capture_format);
369}
370
371VideoCapturerState* CaptureManager::GetCaptureState(
372 VideoCapturer* video_capturer) const {
373 CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
374 if (iter == capture_states_.end()) {
375 return NULL;
376 }
377 return iter->second;
378}
379
380CaptureRenderAdapter* CaptureManager::GetAdapter(
381 VideoCapturer* video_capturer) const {
382 VideoCapturerState* capture_state = GetCaptureState(video_capturer);
383 if (!capture_state) {
384 return NULL;
385 }
386 return capture_state->adapter();
387}
388
389} // namespace cricket