OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/api/videosource.h" | 11 #include "webrtc/api/videosource.h" |
12 | 12 |
13 #include <cstdlib> | 13 #include <cstdlib> |
14 #include <string> | 14 #include <string> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "webrtc/api/mediaconstraintsinterface.h" | 17 #include "webrtc/api/mediaconstraintsinterface.h" |
18 #include "webrtc/base/arraysize.h" | 18 #include "webrtc/base/arraysize.h" |
19 #include "webrtc/pc/channelmanager.h" | |
20 | 19 |
21 using cricket::CaptureState; | 20 using cricket::CaptureState; |
22 using webrtc::MediaConstraintsInterface; | 21 using webrtc::MediaConstraintsInterface; |
23 using webrtc::MediaSourceInterface; | 22 using webrtc::MediaSourceInterface; |
24 | 23 |
25 namespace { | 24 namespace { |
26 | 25 |
27 const double kRoundingTruncation = 0.0005; | 26 const double kRoundingTruncation = 0.0005; |
28 | 27 |
29 enum { | |
30 MSG_VIDEOCAPTURESTATECONNECT, | |
31 MSG_VIDEOCAPTURESTATEDISCONNECT, | |
32 MSG_VIDEOCAPTURESTATECHANGE, | |
33 }; | |
34 | |
35 // Default resolution. If no constraint is specified, this is the resolution we | 28 // Default resolution. If no constraint is specified, this is the resolution we |
36 // will use. | 29 // will use. |
37 static const cricket::VideoFormatPod kDefaultFormat = | 30 static const cricket::VideoFormatPod kDefaultFormat = |
38 {640, 480, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}; | 31 {640, 480, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}; |
39 | 32 |
40 // List of formats used if the camera doesn't support capability enumeration. | 33 // List of formats used if the camera doesn't support capability enumeration. |
41 static const cricket::VideoFormatPod kVideoFormats[] = { | 34 static const cricket::VideoFormatPod kVideoFormats[] = { |
42 {1920, 1080, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, | 35 {1920, 1080, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, |
43 {1280, 720, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, | 36 {1280, 720, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, |
44 {960, 720, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, | 37 {960, 720, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY}, |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 &(options->video_noise_reduction)); | 268 &(options->video_noise_reduction)); |
276 | 269 |
277 return all_valid; | 270 return all_valid; |
278 } | 271 } |
279 | 272 |
280 } // anonymous namespace | 273 } // anonymous namespace |
281 | 274 |
282 namespace webrtc { | 275 namespace webrtc { |
283 | 276 |
284 rtc::scoped_refptr<VideoSource> VideoSource::Create( | 277 rtc::scoped_refptr<VideoSource> VideoSource::Create( |
285 cricket::ChannelManager* channel_manager, | 278 rtc::Thread* worker_thread, |
286 cricket::VideoCapturer* capturer, | 279 cricket::VideoCapturer* capturer, |
287 const webrtc::MediaConstraintsInterface* constraints, | 280 const webrtc::MediaConstraintsInterface* constraints, |
288 bool remote) { | 281 bool remote) { |
289 ASSERT(channel_manager != NULL); | 282 RTC_DCHECK(worker_thread != NULL); |
290 ASSERT(capturer != NULL); | 283 RTC_DCHECK(capturer != NULL); |
291 rtc::scoped_refptr<VideoSource> source(new rtc::RefCountedObject<VideoSource>( | 284 rtc::scoped_refptr<VideoSource> source(new rtc::RefCountedObject<VideoSource>( |
292 channel_manager, capturer, remote)); | 285 worker_thread, capturer, remote)); |
293 source->Initialize(constraints); | 286 source->Initialize(constraints); |
294 return source; | 287 return source; |
295 } | 288 } |
296 | 289 |
297 VideoSource::VideoSource(cricket::ChannelManager* channel_manager, | 290 VideoSource::VideoSource(rtc::Thread* worker_thread, |
298 cricket::VideoCapturer* capturer, | 291 cricket::VideoCapturer* capturer, |
299 bool remote) | 292 bool remote) |
300 : channel_manager_(channel_manager), | 293 : signaling_thread_(rtc::Thread::Current()), |
| 294 worker_thread_(worker_thread), |
301 video_capturer_(capturer), | 295 video_capturer_(capturer), |
| 296 started_(false), |
302 state_(kInitializing), | 297 state_(kInitializing), |
303 remote_(remote) { | 298 remote_(remote) { |
304 channel_manager_->SignalVideoCaptureStateChange.connect( | 299 video_capturer_->SignalStateChange.connect( |
305 this, &VideoSource::OnStateChange); | 300 this, &VideoSource::OnStateChange); |
306 } | 301 } |
307 | 302 |
308 VideoSource::~VideoSource() { | 303 VideoSource::~VideoSource() { |
309 channel_manager_->StopVideoCapture(video_capturer_.get(), format_); | 304 video_capturer_->SignalStateChange.disconnect(this); |
310 channel_manager_->SignalVideoCaptureStateChange.disconnect(this); | 305 Stop(); |
311 } | 306 } |
312 | 307 |
313 void VideoSource::Initialize( | 308 void VideoSource::Initialize( |
314 const webrtc::MediaConstraintsInterface* constraints) { | 309 const webrtc::MediaConstraintsInterface* constraints) { |
315 | |
316 std::vector<cricket::VideoFormat> formats = | 310 std::vector<cricket::VideoFormat> formats = |
317 channel_manager_->GetSupportedFormats(video_capturer_.get()); | 311 *video_capturer_->GetSupportedFormats(); |
318 if (formats.empty()) { | 312 if (formats.empty()) { |
319 if (video_capturer_->IsScreencast()) { | 313 if (video_capturer_->IsScreencast()) { |
320 // The screen capturer can accept any resolution and we will derive the | 314 // The screen capturer can accept any resolution and we will derive the |
321 // format from the constraints if any. | 315 // format from the constraints if any. |
322 // Note that this only affects tab capturing, not desktop capturing, | 316 // Note that this only affects tab capturing, not desktop capturing, |
323 // since the desktop capturer does not respect the VideoFormat passed in. | 317 // since the desktop capturer does not respect the VideoFormat passed in. |
324 formats.push_back(cricket::VideoFormat(kDefaultFormat)); | 318 formats.push_back(cricket::VideoFormat(kDefaultFormat)); |
325 } else { | 319 } else { |
326 // The VideoCapturer implementation doesn't support capability | 320 // The VideoCapturer implementation doesn't support capability |
327 // enumeration. We need to guess what the camera supports. | 321 // enumeration. We need to guess what the camera supports. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 } | 354 } |
361 options_.SetAll(options); | 355 options_.SetAll(options); |
362 options_.is_screencast = rtc::Optional<bool>(video_capturer_->IsScreencast()); | 356 options_.is_screencast = rtc::Optional<bool>(video_capturer_->IsScreencast()); |
363 | 357 |
364 format_ = GetBestCaptureFormat(formats); | 358 format_ = GetBestCaptureFormat(formats); |
365 // Start the camera with our best guess. | 359 // Start the camera with our best guess. |
366 // TODO(perkj): Should we try again with another format it it turns out that | 360 // TODO(perkj): Should we try again with another format it it turns out that |
367 // the camera doesn't produce frames with the correct format? Or will | 361 // the camera doesn't produce frames with the correct format? Or will |
368 // cricket::VideCapturer be able to re-scale / crop to the requested | 362 // cricket::VideCapturer be able to re-scale / crop to the requested |
369 // resolution? | 363 // resolution? |
370 if (!channel_manager_->StartVideoCapture(video_capturer_.get(), format_)) { | 364 if (!worker_thread_->Invoke<bool>( |
| 365 rtc::Bind(&cricket::VideoCapturer::StartCapturing, |
| 366 video_capturer_.get(), format_))) { |
371 SetState(kEnded); | 367 SetState(kEnded); |
372 return; | 368 return; |
373 } | 369 } |
| 370 started_ = true; |
374 // Initialize hasn't succeeded until a successful state change has occurred. | 371 // Initialize hasn't succeeded until a successful state change has occurred. |
375 } | 372 } |
376 | 373 |
377 void VideoSource::Stop() { | 374 void VideoSource::Stop() { |
378 channel_manager_->StopVideoCapture(video_capturer_.get(), format_); | 375 if (!started_) { |
| 376 return; |
| 377 } |
| 378 started_ = false; |
| 379 worker_thread_->Invoke<void>( |
| 380 rtc::Bind(&cricket::VideoCapturer::Stop, |
| 381 video_capturer_.get())); |
379 } | 382 } |
380 | 383 |
381 void VideoSource::Restart() { | 384 void VideoSource::Restart() { |
382 if (!channel_manager_->StartVideoCapture(video_capturer_.get(), format_)) { | 385 if (started_) { |
| 386 return; |
| 387 } |
| 388 if (!worker_thread_->Invoke<bool>( |
| 389 rtc::Bind(&cricket::VideoCapturer::StartCapturing, |
| 390 video_capturer_.get(), format_))) { |
383 SetState(kEnded); | 391 SetState(kEnded); |
384 return; | 392 return; |
385 } | 393 } |
386 for (auto* sink : sinks_) { | 394 started_ = true; |
387 channel_manager_->AddVideoSink(video_capturer_.get(), sink); | |
388 } | |
389 } | 395 } |
390 | 396 |
391 void VideoSource::AddSink( | 397 void VideoSource::AddSink( |
392 rtc::VideoSinkInterface<cricket::VideoFrame>* output) { | 398 rtc::VideoSinkInterface<cricket::VideoFrame>* output) { |
393 sinks_.push_back(output); | 399 // TODO(perkj): Use fake rtc::VideoSinkWants for now. This will change once |
394 channel_manager_->AddVideoSink(video_capturer_.get(), output); | 400 // webrtc::VideoSourceInterface inherit rtc::VideoSourceInterface. |
| 401 worker_thread_->Invoke<void>( |
| 402 rtc::Bind(&cricket::VideoCapturer::AddOrUpdateSink, |
| 403 video_capturer_.get(), output, rtc::VideoSinkWants())); |
395 } | 404 } |
396 | 405 |
397 void VideoSource::RemoveSink( | 406 void VideoSource::RemoveSink( |
398 rtc::VideoSinkInterface<cricket::VideoFrame>* output) { | 407 rtc::VideoSinkInterface<cricket::VideoFrame>* output) { |
399 sinks_.remove(output); | 408 worker_thread_->Invoke<void>( |
400 channel_manager_->RemoveVideoSink(video_capturer_.get(), output); | 409 rtc::Bind(&cricket::VideoCapturer::RemoveSink, |
| 410 video_capturer_.get(), output)); |
401 } | 411 } |
402 | 412 |
403 // OnStateChange listens to the ChannelManager::SignalVideoCaptureStateChange. | 413 // OnStateChange listens to the cricket::VideoCapturer::SignalStateChange. |
404 // This signal is triggered for all video capturers. Not only the one we are | |
405 // interested in. | |
406 void VideoSource::OnStateChange(cricket::VideoCapturer* capturer, | 414 void VideoSource::OnStateChange(cricket::VideoCapturer* capturer, |
407 cricket::CaptureState capture_state) { | 415 cricket::CaptureState capture_state) { |
| 416 if (rtc::Thread::Current() != signaling_thread_) { |
| 417 invoker_.AsyncInvoke<void>( |
| 418 signaling_thread_, rtc::Bind(&VideoSource::OnStateChange, this, |
| 419 capturer, capture_state)); |
| 420 return; |
| 421 } |
| 422 |
408 if (capturer == video_capturer_.get()) { | 423 if (capturer == video_capturer_.get()) { |
409 SetState(GetReadyState(capture_state)); | 424 SetState(GetReadyState(capture_state)); |
410 } | 425 } |
411 } | 426 } |
412 | 427 |
413 void VideoSource::SetState(SourceState new_state) { | 428 void VideoSource::SetState(SourceState new_state) { |
414 // TODO(hbos): Temporarily disabled VERIFY due to webrtc:4776. | |
415 // if (VERIFY(state_ != new_state)) { | |
416 if (state_ != new_state) { | 429 if (state_ != new_state) { |
417 state_ = new_state; | 430 state_ = new_state; |
418 FireOnChanged(); | 431 FireOnChanged(); |
419 } | 432 } |
420 } | 433 } |
421 | 434 |
422 } // namespace webrtc | 435 } // namespace webrtc |
OLD | NEW |