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