| 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 "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); | |
| 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 | |
| 83 const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = { | |
| 84 640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY | |
| 85 }; | |
| 86 | |
| 87 VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter) | |
| 88 : adapter_(adapter), start_count_(1) {} | |
| 89 | |
| 90 // static | |
| 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 | |
| 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 | |
| 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 | |
| 128 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 | |
| 151 int VideoCapturerState::IncCaptureStartRef() { | |
| 152 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 153 return ++start_count_; | |
| 154 } | |
| 155 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 316 bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const { | |
| 317 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 318 return GetCaptureState(video_capturer) != NULL; | |
| 319 } | |
| 320 | |
| 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 | |
| 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 | |
| 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 | |
| 385 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 | |
| 395 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 | |
| OLD | NEW |