From 162c3393bee23f81984041864817f0f8f5b31d16 Mon Sep 17 00:00:00 2001 From: perkj Date: Thu, 11 Feb 2016 02:56:35 -0800 Subject: [PATCH] Revert of Make cricket::VideoCapturer implement VideoSourceInterface (patchset #14 id:300001 of https://codereview.webrtc.org/1655793003/ ) Reason for revert: Needs to revert again unfortunately. There are multiple implementations in Chrome of cricket::VideoCapturer. One is ./../remoting/protocol/webrtc_video_capturer_adapter.cc... https://build.chromium.org/p/chromium.webrtc.fyi/builders/Mac%20Builder/builds/9581/steps/compile/logs/stdio Fun times - I will have to modify this cl after trying it manually out in Chrome. Original issue's description: > This cl introduce a VideoSourceInterface and let cricket::VideoCapturer implement it. > Further more, it adds a VideoBroadcaster than is used for delivering frames to multiple sinks. > > BUG=webrtc:5426 > R=nisse@webrtc.org, pthatcher@webrtc.org > > Committed: https://crrev.com/4d19c5b010473615fa181afa84c6f4b3104e3171 > Cr-Commit-Position: refs/heads/master@{#11567} TBR=pthatcher@google.com,nisse@webrtc.org,pthatcher@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=webrtc:5426 Review URL: https://codereview.webrtc.org/1690893002 Cr-Commit-Position: refs/heads/master@{#11568} --- talk/session/media/channelmanager.cc | 1 + talk/session/media/channelmanager.h | 1 + webrtc/api/androidvideocapturer.cc | 5 +- webrtc/api/remotevideocapturer_unittest.cc | 18 ++++ webrtc/media/base/capturemanager.cc | 58 +++++++--- webrtc/media/base/capturemanager.h | 7 +- webrtc/media/base/capturerenderadapter.cc | 74 ++++++++++++- webrtc/media/base/capturerenderadapter.h | 58 ++++++++++ webrtc/media/base/fakevideorenderer.h | 6 -- webrtc/media/base/videobroadcaster.cc | 82 -------------- webrtc/media/base/videobroadcaster.h | 60 ----------- webrtc/media/base/videocapturer.cc | 34 +++--- webrtc/media/base/videocapturer.h | 29 +++-- webrtc/media/base/videocapturer_unittest.cc | 113 +++++++++----------- webrtc/media/base/videoengine_unittest.h | 15 +++ webrtc/media/base/videosinkinterface.h | 3 +- webrtc/media/base/videosourceinterface.h | 46 -------- webrtc/media/media.gyp | 4 +- webrtc/media/webrtc/webrtcvideocapturer.cc | 19 ++-- webrtc/media/webrtc/webrtcvideocapturer.h | 17 +-- webrtc/media/webrtc/webrtcvideoengine2.cc | 46 ++++---- webrtc/media/webrtc/webrtcvideoengine2.h | 10 +- 22 files changed, 352 insertions(+), 354 deletions(-) create mode 100644 webrtc/media/base/capturerenderadapter.h delete mode 100644 webrtc/media/base/videobroadcaster.cc delete mode 100644 webrtc/media/base/videobroadcaster.h delete mode 100644 webrtc/media/base/videosourceinterface.h diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc index 9cac1451a2..8124f28364 100644 --- a/talk/session/media/channelmanager.cc +++ b/talk/session/media/channelmanager.cc @@ -103,6 +103,7 @@ void ChannelManager::Construct(MediaEngineInterface* me, main_thread_ = rtc::Thread::Current(); worker_thread_ = worker_thread; audio_output_volume_ = kNotSetOutputVolume; + local_renderer_ = NULL; capturing_ = false; enable_rtx_ = false; diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h index 7e4c342b34..de8555208f 100644 --- a/talk/session/media/channelmanager.h +++ b/talk/session/media/channelmanager.h @@ -231,6 +231,7 @@ class ChannelManager : public rtc::MessageHandler, DataChannels data_channels_; int audio_output_volume_; + VideoRenderer* local_renderer_; bool enable_rtx_; bool capturing_; diff --git a/webrtc/api/androidvideocapturer.cc b/webrtc/api/androidvideocapturer.cc index 33e0d41703..bab1402eda 100644 --- a/webrtc/api/androidvideocapturer.cc +++ b/webrtc/api/androidvideocapturer.cc @@ -27,8 +27,7 @@ namespace webrtc { // for ref counted I420 frames instead of this hack. class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory { public: - explicit FrameFactory( - const rtc::scoped_refptr& delegate) + FrameFactory(const rtc::scoped_refptr& delegate) : delegate_(delegate) { // Create a CapturedFrame that only contains header information, not the // actual pixel data. @@ -142,6 +141,8 @@ AndroidVideoCapturer::AndroidVideoCapturer( formats.push_back(format); } SetSupportedFormats(formats); + // Do not apply frame rotation by default. + SetApplyRotation(false); } AndroidVideoCapturer::~AndroidVideoCapturer() { diff --git a/webrtc/api/remotevideocapturer_unittest.cc b/webrtc/api/remotevideocapturer_unittest.cc index bc5e075449..5d9672dbe9 100644 --- a/webrtc/api/remotevideocapturer_unittest.cc +++ b/webrtc/api/remotevideocapturer_unittest.cc @@ -34,10 +34,13 @@ class RemoteVideoCapturerTest : public testing::Test, virtual void SetUp() { capturer_.SignalStateChange.connect( this, &RemoteVideoCapturerTest::OnStateChange); + capturer_.SignalVideoFrame.connect( + this, &RemoteVideoCapturerTest::OnVideoFrame); } ~RemoteVideoCapturerTest() { capturer_.SignalStateChange.disconnect(this); + capturer_.SignalVideoFrame.disconnect(this); } int captured_frame_num() const { @@ -57,6 +60,11 @@ class RemoteVideoCapturerTest : public testing::Test, capture_state_ = capture_state; } + void OnVideoFrame(VideoCapturer* capturer, const VideoFrame* frame) { + EXPECT_EQ(&capturer_, capturer); + ++captured_frame_num_; + } + int captured_frame_num_; CaptureState capture_state_; }; @@ -95,3 +103,13 @@ TEST_F(RemoteVideoCapturerTest, GetBestCaptureFormat) { EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best_format)); EXPECT_EQ(expected_format, best_format); } + +TEST_F(RemoteVideoCapturerTest, InputFrame) { + EXPECT_EQ(0, captured_frame_num()); + + cricket::WebRtcVideoFrame test_frame; + capturer_.SignalVideoFrame(&capturer_, &test_frame); + EXPECT_EQ(1, captured_frame_num()); + capturer_.SignalVideoFrame(&capturer_, &test_frame); + EXPECT_EQ(2, captured_frame_num()); +} diff --git a/webrtc/media/base/capturemanager.cc b/webrtc/media/base/capturemanager.cc index 3628fb306d..689b6d7620 100644 --- a/webrtc/media/base/capturemanager.cc +++ b/webrtc/media/base/capturemanager.cc @@ -23,7 +23,7 @@ class VideoCapturerState { public: static const VideoFormatPod kDefaultCaptureFormat; - explicit VideoCapturerState(VideoCapturer* capturer); + static VideoCapturerState* Create(VideoCapturer* video_capturer); ~VideoCapturerState() {} void AddCaptureResolution(const VideoFormat& desired_format); @@ -32,9 +32,13 @@ class VideoCapturerState { int IncCaptureStartRef(); int DecCaptureStartRef(); + CaptureRenderAdapter* adapter() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return adapter_.get(); + } VideoCapturer* GetVideoCapturer() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return video_capturer_; + return adapter()->video_capturer(); } int start_count() const { @@ -49,9 +53,11 @@ class VideoCapturerState { }; typedef std::vector CaptureFormats; - rtc::ThreadChecker thread_checker_; + explicit VideoCapturerState(CaptureRenderAdapter* adapter); + + rtc::ThreadChecker thread_checker_; + rtc::scoped_ptr adapter_; - VideoCapturer* video_capturer_; int start_count_; CaptureFormats capture_formats_; }; @@ -60,8 +66,17 @@ const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = { 640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY }; -VideoCapturerState::VideoCapturerState(VideoCapturer* capturer) - : video_capturer_(capturer), start_count_(1) {} +VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter) + : adapter_(adapter), start_count_(1) {} + +// static +VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) { + CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer); + if (!adapter) { + return NULL; + } + return new VideoCapturerState(adapter); +} void VideoCapturerState::AddCaptureResolution( const VideoFormat& desired_format) { @@ -261,10 +276,11 @@ void CaptureManager::AddVideoSink(VideoCapturer* video_capturer, if (!video_capturer || !sink) { return; } - rtc::VideoSinkWants wants; - // Renderers must be able to apply rotation. - wants.rotation_applied = false; - video_capturer->AddOrUpdateSink(sink, wants); + CaptureRenderAdapter* adapter = GetAdapter(video_capturer); + if (!adapter) { + return; + } + adapter->AddSink(sink); } void CaptureManager::RemoveVideoSink( @@ -274,7 +290,11 @@ void CaptureManager::RemoveVideoSink( if (!video_capturer || !sink) { return; } - video_capturer->RemoveSink(sink); + CaptureRenderAdapter* adapter = GetAdapter(video_capturer); + if (!adapter) { + return; + } + adapter->RemoveSink(sink); } bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const { @@ -284,7 +304,11 @@ bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const { bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) { RTC_DCHECK(thread_checker_.CalledOnValidThread()); - VideoCapturerState* capture_state = new VideoCapturerState(video_capturer); + VideoCapturerState* capture_state = + VideoCapturerState::Create(video_capturer); + if (!capture_state) { + return false; + } capture_states_[video_capturer] = capture_state; SignalCapturerStateChange.repeat(video_capturer->SignalStateChange); return true; @@ -352,4 +376,14 @@ VideoCapturerState* CaptureManager::GetCaptureState( return iter->second; } +CaptureRenderAdapter* CaptureManager::GetAdapter( + VideoCapturer* video_capturer) const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + VideoCapturerState* capture_state = GetCaptureState(video_capturer); + if (!capture_state) { + return NULL; + } + return capture_state->adapter(); +} + } // namespace cricket diff --git a/webrtc/media/base/capturemanager.h b/webrtc/media/base/capturemanager.h index 93f8e18610..c4f1f69fae 100644 --- a/webrtc/media/base/capturemanager.h +++ b/webrtc/media/base/capturemanager.h @@ -29,13 +29,13 @@ #include "webrtc/base/sigslotrepeater.h" #include "webrtc/base/thread_checker.h" +#include "webrtc/media/base/capturerenderadapter.h" #include "webrtc/media/base/videocommon.h" -#include "webrtc/media/base/videocapturer.h" -#include "webrtc/media/base/videosinkinterface.h" namespace cricket { -class VideoFrame; +class VideoCapturer; +class VideoRenderer; class VideoCapturerState; class CaptureManager : public sigslot::has_slots<> { @@ -80,6 +80,7 @@ class CaptureManager : public sigslot::has_slots<> { VideoCapturer* video_capturer); VideoCapturerState* GetCaptureState(VideoCapturer* video_capturer) const; + CaptureRenderAdapter* GetAdapter(VideoCapturer* video_capturer) const; rtc::ThreadChecker thread_checker_; CaptureStates capture_states_; diff --git a/webrtc/media/base/capturerenderadapter.cc b/webrtc/media/base/capturerenderadapter.cc index 4eb738b0db..f8d28f792f 100644 --- a/webrtc/media/base/capturerenderadapter.cc +++ b/webrtc/media/base/capturerenderadapter.cc @@ -8,4 +8,76 @@ * be found in the AUTHORS file in the root of the source tree. */ -// TODO(perkj): Remove this dummy file once Chrome is not depending on it. +#include "webrtc/media/base/capturerenderadapter.h" + +#include "webrtc/base/logging.h" +#include "webrtc/media/base/videocapturer.h" +#include "webrtc/media/base/videorenderer.h" + +namespace cricket { + +CaptureRenderAdapter::CaptureRenderAdapter(VideoCapturer* video_capturer) + : video_capturer_(video_capturer) { +} + +CaptureRenderAdapter::~CaptureRenderAdapter() { + // Since the signal we're connecting to is multi-threaded, + // disconnect_all() will block until all calls are serviced, meaning any + // outstanding calls to OnVideoFrame will be done when this is done, and no + // more calls will be serviced by this. + // We do this explicitly instead of just letting the has_slots<> destructor + // take care of it because we need to do this *before* sinks_ is + // cleared by the destructor; otherwise we could mess with it while + // OnVideoFrame is running. + // We *don't* take capture_crit_ here since it could deadlock with the lock + // taken by the video frame signal. + disconnect_all(); +} + +CaptureRenderAdapter* CaptureRenderAdapter::Create( + VideoCapturer* video_capturer) { + if (!video_capturer) { + return NULL; + } + CaptureRenderAdapter* return_value = new CaptureRenderAdapter(video_capturer); + return_value->Init(); // Can't fail. + return return_value; +} + +void CaptureRenderAdapter::AddSink(rtc::VideoSinkInterface* sink) { + RTC_DCHECK(sink); + + rtc::CritScope cs(&capture_crit_); + // This implements set semantics, the same renderer can only be + // added once. + // TODO(nisse): Is this really needed? + if (std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end()) + sinks_.push_back(sink); +} + +void CaptureRenderAdapter::RemoveSink( + rtc::VideoSinkInterface* sink) { + RTC_DCHECK(sink); + + rtc::CritScope cs(&capture_crit_); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); +} + +void CaptureRenderAdapter::Init() { + video_capturer_->SignalVideoFrame.connect( + this, + &CaptureRenderAdapter::OnVideoFrame); +} + +void CaptureRenderAdapter::OnVideoFrame(VideoCapturer* capturer, + const VideoFrame* video_frame) { + rtc::CritScope cs(&capture_crit_); + if (sinks_.empty()) { + return; + } + + for (auto* sink : sinks_) + sink->OnFrame(*video_frame); +} + +} // namespace cricket diff --git a/webrtc/media/base/capturerenderadapter.h b/webrtc/media/base/capturerenderadapter.h new file mode 100644 index 0000000000..ea457688ef --- /dev/null +++ b/webrtc/media/base/capturerenderadapter.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains the class CaptureRenderAdapter. The class connects a +// VideoCapturer to any number of VideoRenders such that the former feeds the +// latter. +// CaptureRenderAdapter is Thread-unsafe. This means that none of its APIs may +// be called concurrently. + +#ifndef WEBRTC_MEDIA_BASE_CAPTURERENDERADAPTER_H_ +#define WEBRTC_MEDIA_BASE_CAPTURERENDERADAPTER_H_ + +#include + +#include "webrtc/base/criticalsection.h" +#include "webrtc/base/sigslot.h" +#include "webrtc/media/base/videocapturer.h" +#include "webrtc/media/base/videosinkinterface.h" + +namespace cricket { + +class VideoCapturer; +class VideoProcessor; + +class CaptureRenderAdapter : public sigslot::has_slots<> { + public: + static CaptureRenderAdapter* Create(VideoCapturer* video_capturer); + ~CaptureRenderAdapter(); + + void AddSink(rtc::VideoSinkInterface* sink); + void RemoveSink(rtc::VideoSinkInterface* sink); + + VideoCapturer* video_capturer() { return video_capturer_; } + private: + + explicit CaptureRenderAdapter(VideoCapturer* video_capturer); + void Init(); + + // Callback for frames received from the capturer. + void OnVideoFrame(VideoCapturer* capturer, const VideoFrame* video_frame); + + // Just pointers since ownership is not handed over to this class. + std::vector*> sinks_; + VideoCapturer* video_capturer_; + // Critical section synchronizing the capture thread. + rtc::CriticalSection capture_crit_; +}; + +} // namespace cricket + +#endif // WEBRTC_MEDIA_BASE_CAPTURERENDERADAPTER_H_ diff --git a/webrtc/media/base/fakevideorenderer.h b/webrtc/media/base/fakevideorenderer.h index 0854d0ce39..bc82cbaabf 100644 --- a/webrtc/media/base/fakevideorenderer.h +++ b/webrtc/media/base/fakevideorenderer.h @@ -43,7 +43,6 @@ class FakeVideoRenderer : public VideoRenderer { ++num_rendered_frames_; width_ = static_cast(frame->GetWidth()); height_ = static_cast(frame->GetHeight()); - rotation_ = frame->GetVideoRotation(); SignalRenderFrame(frame); return true; } @@ -57,10 +56,6 @@ class FakeVideoRenderer : public VideoRenderer { rtc::CritScope cs(&crit_); return height_; } - int rotation() const { - rtc::CritScope cs(&crit_); - return rotation_; - } int num_rendered_frames() const { rtc::CritScope cs(&crit_); return num_rendered_frames_; @@ -128,7 +123,6 @@ class FakeVideoRenderer : public VideoRenderer { int errors_; int width_; int height_; - webrtc::VideoRotation rotation_; int num_rendered_frames_; bool black_frame_; rtc::CriticalSection crit_; diff --git a/webrtc/media/base/videobroadcaster.cc b/webrtc/media/base/videobroadcaster.cc deleted file mode 100644 index e369ee07c6..0000000000 --- a/webrtc/media/base/videobroadcaster.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/media/base/videobroadcaster.h" - -#include "webrtc/base/checks.h" - -namespace rtc { - -VideoBroadcaster::VideoBroadcaster() { - thread_checker_.DetachFromThread(); -} - -void VideoBroadcaster::AddOrUpdateSink( - VideoSinkInterface* sink, - const VideoSinkWants& wants) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - RTC_DCHECK(sink != nullptr); - - SinkPair* sink_pair = FindSinkPair(sink); - if (!sink_pair) { - sinks_.push_back(SinkPair(sink, wants)); - } else { - sink_pair->wants = wants; - } - - // Rotation must be applied by the source if one sink wants it. - current_wants_.rotation_applied = false; - for (auto& sink_pair : sinks_) { - current_wants_.rotation_applied |= sink_pair.wants.rotation_applied; - } -} - -void VideoBroadcaster::RemoveSink( - VideoSinkInterface* sink) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - RTC_DCHECK(sink != nullptr); - RTC_DCHECK(FindSinkPair(sink)); - - sinks_.erase(std::remove_if(sinks_.begin(), sinks_.end(), - [sink](const SinkPair& sink_pair) { - return sink_pair.sink == sink; - }), - sinks_.end()); -} - -bool VideoBroadcaster::frame_wanted() const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return !sinks_.empty(); -} - -VideoSinkWants VideoBroadcaster::wants() const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return current_wants_; -} - -void VideoBroadcaster::OnFrame(const cricket::VideoFrame& frame) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - for (auto& sink_pair : sinks_) { - sink_pair.sink->OnFrame(frame); - } -} - -VideoBroadcaster::SinkPair* VideoBroadcaster::FindSinkPair( - const VideoSinkInterface* sink) { - auto sink_pair_it = std::find_if( - sinks_.begin(), sinks_.end(), - [sink](const SinkPair& sink_pair) { return sink_pair.sink == sink; }); - if (sink_pair_it != sinks_.end()) { - return &*sink_pair_it; - } - return nullptr; -} - -} // namespace rtc diff --git a/webrtc/media/base/videobroadcaster.h b/webrtc/media/base/videobroadcaster.h deleted file mode 100644 index 63c22730c7..0000000000 --- a/webrtc/media/base/videobroadcaster.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_MEDIA_BASE_VIDEOBROADCASTER_H_ -#define WEBRTC_MEDIA_BASE_VIDEOBROADCASTER_H_ - -#include -#include - -#include "webrtc/base/thread_checker.h" -#include "webrtc/media/base/videoframe.h" -#include "webrtc/media/base/videosinkinterface.h" -#include "webrtc/media/base/videosourceinterface.h" - -namespace rtc { - -class VideoBroadcaster : public VideoSourceInterface, - public VideoSinkInterface { - public: - VideoBroadcaster(); - void AddOrUpdateSink(VideoSinkInterface* sink, - const VideoSinkWants& wants) override; - void RemoveSink(VideoSinkInterface* sink) override; - - // Returns true if the next frame will be delivered to at least one sink. - bool frame_wanted() const; - - // Returns VideoSinkWants a source is requested to fulfill. They are - // aggregated by all VideoSinkWants from all sinks. - VideoSinkWants wants() const; - - void OnFrame(const cricket::VideoFrame& frame) override; - - protected: - struct SinkPair { - SinkPair(VideoSinkInterface* sink, - VideoSinkWants wants) - : sink(sink), wants(wants) {} - VideoSinkInterface* sink; - VideoSinkWants wants; - }; - SinkPair* FindSinkPair(const VideoSinkInterface* sink); - - ThreadChecker thread_checker_; - - VideoSinkWants current_wants_; - - std::vector sinks_; -}; - -} // namespace rtc - -#endif // WEBRTC_MEDIA_BASE_VIDEOBROADCASTER_H_ diff --git a/webrtc/media/base/videocapturer.cc b/webrtc/media/base/videocapturer.cc index 36a5579580..df78ed4695 100644 --- a/webrtc/media/base/videocapturer.cc +++ b/webrtc/media/base/videocapturer.cc @@ -226,6 +226,16 @@ bool VideoCapturer::MuteToBlackThenPause(bool muted) { return Pause(false); } +// Note that the last caller decides whether rotation should be applied if there +// are multiple send streams using the same camera. +bool VideoCapturer::SetApplyRotation(bool enable) { + apply_rotation_ = enable; + if (frame_factory_) { + frame_factory_->SetApplyRotation(apply_rotation_); + } + return true; +} + void VideoCapturer::SetSupportedFormats( const std::vector& formats) { supported_formats_ = formats; @@ -313,25 +323,6 @@ void VideoCapturer::GetStats(VariableInfo* adapt_drops_stats, frame_time_data_.Reset(); } -void VideoCapturer::RemoveSink( - rtc::VideoSinkInterface* sink) { - broadcaster_.RemoveSink(sink); -} - -void VideoCapturer::AddOrUpdateSink( - rtc::VideoSinkInterface* sink, - const rtc::VideoSinkWants& wants) { - broadcaster_.AddOrUpdateSink(sink, wants); - OnSinkWantsChanged(broadcaster_.wants()); -} - -void VideoCapturer::OnSinkWantsChanged(const rtc::VideoSinkWants& wants) { - apply_rotation_ = wants.rotation_applied; - if (frame_factory_) { - frame_factory_->SetApplyRotation(apply_rotation_); - } -} - void VideoCapturer::OnFrameCaptured(VideoCapturer*, const CapturedFrame* captured_frame) { if (muted_) { @@ -342,7 +333,7 @@ void VideoCapturer::OnFrameCaptured(VideoCapturer*, } } - if (!broadcaster_.frame_wanted()) { + if (SignalVideoFrame.is_empty()) { return; } @@ -525,7 +516,8 @@ void VideoCapturer::OnFrameCaptured(VideoCapturer*, // TODO(pthatcher): Use frame_factory_->CreateBlackFrame() instead. adapted_frame->SetToBlack(); } - broadcaster_.OnFrame(*adapted_frame.get()); + SignalVideoFrame(this, adapted_frame.get()); + UpdateStats(captured_frame); } diff --git a/webrtc/media/base/videocapturer.h b/webrtc/media/base/videocapturer.h index 3addd8f05d..3b0d05e86e 100644 --- a/webrtc/media/base/videocapturer.h +++ b/webrtc/media/base/videocapturer.h @@ -19,7 +19,6 @@ #include "webrtc/base/basictypes.h" #include "webrtc/base/criticalsection.h" -#include "webrtc/media/base/videosourceinterface.h" #include "webrtc/base/messagehandler.h" #include "webrtc/base/rollingaccumulator.h" #include "webrtc/base/scoped_ptr.h" @@ -28,7 +27,6 @@ #include "webrtc/base/timing.h" #include "webrtc/media/base/mediachannel.h" #include "webrtc/media/base/videoadapter.h" -#include "webrtc/media/base/videobroadcaster.h" #include "webrtc/media/base/videocommon.h" #include "webrtc/media/base/videoframefactory.h" #include "webrtc/media/devices/devicemanager.h" @@ -75,7 +73,7 @@ struct CapturedFrame { // time with nanosecond units. uint32_t data_size; // number of bytes of the frame data - webrtc::VideoRotation rotation; // rotation in degrees of the frame. + webrtc::VideoRotation rotation; // rotation in degrees of the frame. void* data; // pointer to the frame data. This object allocates the // memory or points to an existing memory. @@ -110,9 +108,9 @@ struct CapturedFrame { // media engine thread). Hence, the VideoCapture subclasses dont need to be // thread safe. // -class VideoCapturer : public sigslot::has_slots<>, - public rtc::MessageHandler, - public rtc::VideoSourceInterface { +class VideoCapturer + : public sigslot::has_slots<>, + public rtc::MessageHandler { public: // All signals are marshalled to |thread| or the creating thread if // none is provided. @@ -199,6 +197,11 @@ class VideoCapturer : public sigslot::has_slots<>, return capture_state_; } + // Tells videocapturer whether to apply the pending rotation. By default, the + // rotation is applied and the generated frame is up right. When set to false, + // generated frames will carry the rotation information from + // SetCaptureRotation. Return value indicates whether this operation succeeds. + virtual bool SetApplyRotation(bool enable); virtual bool GetApplyRotation() { return apply_rotation_; } // Returns true if the capturer is screencasting. This can be used to @@ -237,6 +240,10 @@ class VideoCapturer : public sigslot::has_slots<>, // Signal the captured frame to downstream. sigslot::signal2 SignalFrameCaptured; + // Signal the captured and possibly adapted frame to downstream consumers + // such as the encoder. + sigslot::signal2 SignalVideoFrame; // If true, run video adaptation. By default, video adaptation is enabled // and users must call video_adapter()->OnOutputFormatRequest() @@ -262,16 +269,7 @@ class VideoCapturer : public sigslot::has_slots<>, VariableInfo* frame_time_stats, VideoFormat* last_captured_frame_format); - // Implements VideoSourceInterface - void AddOrUpdateSink(rtc::VideoSinkInterface* sink, - const rtc::VideoSinkWants& wants) override; - void RemoveSink(rtc::VideoSinkInterface* sink) override; - protected: - // OnSinkWantsChanged can be overridden to change the default behavior - // when a sink changes its VideoSinkWants by calling AddOrUpdateSink. - virtual void OnSinkWantsChanged(const rtc::VideoSinkWants& wants); - // Callback attached to SignalFrameCaptured where SignalVideoFrames is called. void OnFrameCaptured(VideoCapturer* video_capturer, const CapturedFrame* captured_frame); @@ -346,7 +344,6 @@ class VideoCapturer : public sigslot::has_slots<>, bool muted_; int black_frame_count_down_; - rtc::VideoBroadcaster broadcaster_; bool enable_video_adapter_; CoordinatedVideoAdapter video_adapter_; diff --git a/webrtc/media/base/videocapturer_unittest.cc b/webrtc/media/base/videocapturer_unittest.cc index f385d59551..cbd92c5b8c 100644 --- a/webrtc/media/base/videocapturer_unittest.cc +++ b/webrtc/media/base/videocapturer_unittest.cc @@ -35,13 +35,29 @@ class VideoCapturerTest public testing::Test { public: VideoCapturerTest() - : capture_state_(cricket::CS_STOPPED), num_state_changes_(0) { + : capture_state_(cricket::CS_STOPPED), + num_state_changes_(0), + video_frames_received_(0), + expects_rotation_applied_(true) { + capturer_.SignalVideoFrame.connect(this, &VideoCapturerTest::OnVideoFrame); capturer_.SignalStateChange.connect(this, &VideoCapturerTest::OnStateChange); - capturer_.AddOrUpdateSink(&renderer_, rtc::VideoSinkWants()); + } + + void set_expected_compensation(bool compensation) { + expects_rotation_applied_ = compensation; } protected: + void OnVideoFrame(cricket::VideoCapturer*, const cricket::VideoFrame* frame) { + ++video_frames_received_; + if (expects_rotation_applied_) { + EXPECT_EQ(webrtc::kVideoRotation_0, frame->GetRotation()); + } else { + EXPECT_EQ(capturer_.GetRotation(), frame->GetRotation()); + } + renderer_.RenderFrame(frame); + } void OnStateChange(cricket::VideoCapturer*, cricket::CaptureState capture_state) { capture_state_ = capture_state; @@ -49,10 +65,14 @@ class VideoCapturerTest } cricket::CaptureState capture_state() { return capture_state_; } int num_state_changes() { return num_state_changes_; } + int video_frames_received() const { + return video_frames_received_; + } cricket::FakeVideoCapturer capturer_; cricket::CaptureState capture_state_; int num_state_changes_; + int video_frames_received_; cricket::FakeVideoRenderer renderer_; bool expects_rotation_applied_; }; @@ -129,9 +149,9 @@ TEST_F(VideoCapturerTest, CameraOffOnMute) { cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420))); EXPECT_TRUE(capturer_.IsRunning()); - EXPECT_EQ(0, renderer_.num_rendered_frames()); + EXPECT_EQ(0, video_frames_received()); EXPECT_TRUE(capturer_.CaptureFrame()); - EXPECT_EQ(1, renderer_.num_rendered_frames()); + EXPECT_EQ(1, video_frames_received()); EXPECT_FALSE(capturer_.IsMuted()); // Mute the camera and expect black output frame. @@ -141,13 +161,13 @@ TEST_F(VideoCapturerTest, CameraOffOnMute) { EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_TRUE(renderer_.black_frame()); } - EXPECT_EQ(32, renderer_.num_rendered_frames()); + EXPECT_EQ(32, video_frames_received()); EXPECT_EQ_WAIT(cricket::CS_PAUSED, capturer_.capture_state(), kTimeout); // Verify that the camera is off. EXPECT_FALSE(capturer_.CaptureFrame()); - EXPECT_EQ(32, renderer_.num_rendered_frames()); + EXPECT_EQ(32, video_frames_received()); // Unmute the camera and expect non-black output frame. capturer_.MuteToBlackThenPause(false); @@ -156,7 +176,7 @@ TEST_F(VideoCapturerTest, CameraOffOnMute) { capturer_.capture_state(), kTimeout); EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_FALSE(renderer_.black_frame()); - EXPECT_EQ(33, renderer_.num_rendered_frames()); + EXPECT_EQ(33, video_frames_received()); } TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) { @@ -183,7 +203,7 @@ TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) { EXPECT_EQ(kHeight, renderer_.height()); } -TEST_F(VideoCapturerTest, TestRotationAppliedBySource) { +TEST_F(VideoCapturerTest, TestRotationPending) { int kWidth = 800; int kHeight = 400; int frame_count = 0; @@ -194,7 +214,6 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySource) { cricket::FOURCC_I420)); capturer_.ResetSupportedFormats(formats); - // capturer_ should compensate rotation as default. capturer_.UpdateAspectRatio(400, 200); @@ -215,7 +234,6 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySource) { // Swapped width and height EXPECT_EQ(kWidth, renderer_.height()); EXPECT_EQ(kHeight, renderer_.width()); - EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation()); capturer_.SetRotation(webrtc::kVideoRotation_270); EXPECT_TRUE(capturer_.CaptureFrame()); @@ -223,7 +241,6 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySource) { // Swapped width and height EXPECT_EQ(kWidth, renderer_.height()); EXPECT_EQ(kHeight, renderer_.width()); - EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation()); capturer_.SetRotation(webrtc::kVideoRotation_180); EXPECT_TRUE(capturer_.CaptureFrame()); @@ -231,10 +248,9 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySource) { // Back to normal width and height EXPECT_EQ(kWidth, renderer_.width()); EXPECT_EQ(kHeight, renderer_.height()); - EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation()); } -TEST_F(VideoCapturerTest, TestRotationAppliedBySink) { +TEST_F(VideoCapturerTest, TestRotationApplied) { int kWidth = 800; int kHeight = 400; @@ -244,12 +260,10 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySink) { cricket::FOURCC_I420)); capturer_.ResetSupportedFormats(formats); - rtc::VideoSinkWants wants; // capturer_ should not compensate rotation. - wants.rotation_applied = false; - capturer_.AddOrUpdateSink(&renderer_, wants); - + capturer_.SetApplyRotation(false); capturer_.UpdateAspectRatio(400, 200); + set_expected_compensation(false); EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat( @@ -267,64 +281,18 @@ TEST_F(VideoCapturerTest, TestRotationAppliedBySink) { capturer_.SetRotation(webrtc::kVideoRotation_0); EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(capturer_.GetRotation(), renderer_.rotation()); capturer_.SetRotation(webrtc::kVideoRotation_90); EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(capturer_.GetRotation(), renderer_.rotation()); capturer_.SetRotation(webrtc::kVideoRotation_180); EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(capturer_.GetRotation(), renderer_.rotation()); capturer_.SetRotation(webrtc::kVideoRotation_270); EXPECT_TRUE(capturer_.CaptureFrame()); EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(capturer_.GetRotation(), renderer_.rotation()); -} - -TEST_F(VideoCapturerTest, TestRotationAppliedBySourceWhenDifferentWants) { - int kWidth = 800; - int kHeight = 400; - - std::vector formats; - formats.push_back(cricket::VideoFormat(kWidth, kHeight, - cricket::VideoFormat::FpsToInterval(5), - cricket::FOURCC_I420)); - - capturer_.ResetSupportedFormats(formats); - rtc::VideoSinkWants wants; - // capturer_ should not compensate rotation. - wants.rotation_applied = false; - capturer_.AddOrUpdateSink(&renderer_, wants); - - capturer_.UpdateAspectRatio(400, 200); - - EXPECT_EQ(cricket::CS_RUNNING, - capturer_.Start(cricket::VideoFormat( - kWidth, kHeight, cricket::VideoFormat::FpsToInterval(30), - cricket::FOURCC_I420))); - EXPECT_TRUE(capturer_.IsRunning()); - EXPECT_EQ(0, renderer_.num_rendered_frames()); - - int frame_count = 0; - capturer_.SetRotation(webrtc::kVideoRotation_90); - EXPECT_TRUE(capturer_.CaptureFrame()); - EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(capturer_.GetRotation(), renderer_.rotation()); - - // Add another sink that wants frames to be rotated. - cricket::FakeVideoRenderer renderer2; - wants.rotation_applied = true; - capturer_.AddOrUpdateSink(&renderer2, wants); - - EXPECT_TRUE(capturer_.CaptureFrame()); - EXPECT_EQ(++frame_count, renderer_.num_rendered_frames()); - EXPECT_EQ(1, renderer2.num_rendered_frames()); - EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation()); - EXPECT_EQ(webrtc::kVideoRotation_0, renderer2.rotation()); } TEST_F(VideoCapturerTest, ScreencastScaledSuperLarge) { @@ -747,6 +715,25 @@ TEST_F(VideoCapturerTest, TestRequest16x10_9) { EXPECT_EQ(360, best.height); } +// If HAVE_WEBRTC_VIDEO is not defined the video capturer will not be able to +// provide OnVideoFrame-callbacks since they require cricket::CapturedFrame to +// be decoded as a cricket::VideoFrame (i.e. an I420 frame). This functionality +// only exist if HAVE_WEBRTC_VIDEO is defined below. I420 frames are also a +// requirement for the VideoProcessors so they will not be called either. +#if defined(HAVE_WEBRTC_VIDEO) +TEST_F(VideoCapturerTest, VideoFrame) { + EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat( + 640, + 480, + cricket::VideoFormat::FpsToInterval(30), + cricket::FOURCC_I420))); + EXPECT_TRUE(capturer_.IsRunning()); + EXPECT_EQ(0, video_frames_received()); + EXPECT_TRUE(capturer_.CaptureFrame()); + EXPECT_EQ(1, video_frames_received()); +} +#endif // HAVE_WEBRTC_VIDEO + bool HdFormatInList(const std::vector& formats) { for (std::vector::const_iterator found = formats.begin(); found != formats.end(); ++found) { diff --git a/webrtc/media/base/videoengine_unittest.h b/webrtc/media/base/videoengine_unittest.h index 8a372a35be..a81fde99aa 100644 --- a/webrtc/media/base/videoengine_unittest.h +++ b/webrtc/media/base/videoengine_unittest.h @@ -86,6 +86,21 @@ class VideoEngineOverride : public T { virtual ~VideoEngineOverride() { } bool is_camera_on() const { return T::GetVideoCapturer()->IsRunning(); } + void set_has_senders(bool has_senders) { + cricket::VideoCapturer* video_capturer = T::GetVideoCapturer(); + if (has_senders) { + video_capturer->SignalVideoFrame.connect(this, + &VideoEngineOverride::OnLocalFrame); + } else { + video_capturer->SignalVideoFrame.disconnect(this); + } + } + void OnLocalFrame(cricket::VideoCapturer*, + const cricket::VideoFrame*) { + } + void OnLocalFrameFormat(cricket::VideoCapturer*, + const cricket::VideoFormat*) { + } void TriggerMediaFrame(uint32_t ssrc, cricket::VideoFrame* frame, diff --git a/webrtc/media/base/videosinkinterface.h b/webrtc/media/base/videosinkinterface.h index bb41bdb281..9b8ba31862 100644 --- a/webrtc/media/base/videosinkinterface.h +++ b/webrtc/media/base/videosinkinterface.h @@ -17,8 +17,9 @@ template class VideoSinkInterface { public: virtual void OnFrame(const VideoFrameT& frame) = 0; + protected: - virtual ~VideoSinkInterface() {} + ~VideoSinkInterface() {} }; } // namespace rtc diff --git a/webrtc/media/base/videosourceinterface.h b/webrtc/media/base/videosourceinterface.h deleted file mode 100644 index 1462458543..0000000000 --- a/webrtc/media/base/videosourceinterface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_MEDIA_BASE_VIDEOSOURCEINTERFACE_H_ -#define WEBRTC_MEDIA_BASE_VIDEOSOURCEINTERFACE_H_ - -#include "webrtc/media/base/videosinkinterface.h" -#include "webrtc/base/callback.h" - -namespace rtc { - -// VideoSinkWants is used for notifying the source of properties a video frame -// should have when it is delivered to a certain sink. -struct VideoSinkWants { - bool operator==(const VideoSinkWants& rh) const { - return rotation_applied == rh.rotation_applied; - } - bool operator!=(const VideoSinkWants& rh) const { return !operator==(rh); } - - // Tells the source whether the sink wants frames with rotation applied. - // By default, the rotation is applied by the source. - bool rotation_applied = true; -}; - -template -class VideoSourceInterface { - public: - virtual void AddOrUpdateSink(VideoSinkInterface* sink, - const VideoSinkWants& wants) = 0; - // RemoveSink must guarantee that at the time the method returns, - // there is no current and no future calls to VideoSinkInterface::OnFrame. - virtual void RemoveSink(VideoSinkInterface* sink) = 0; - - protected: - virtual ~VideoSourceInterface() {} -}; - -} // namespace rtc -#endif // WEBRTC_MEDIA_BASE_VIDEOSOURCEINTERFACE_H_ diff --git a/webrtc/media/media.gyp b/webrtc/media/media.gyp index c1a230136e..7a2ab1c892 100644 --- a/webrtc/media/media.gyp +++ b/webrtc/media/media.gyp @@ -35,6 +35,8 @@ 'base/audiorenderer.h', 'base/capturemanager.cc', 'base/capturemanager.h', + 'base/capturerenderadapter.cc', + 'base/capturerenderadapter.h', 'base/codec.cc', 'base/codec.h', 'base/constants.cc', @@ -62,8 +64,6 @@ 'base/turnutils.h', 'base/videoadapter.cc', 'base/videoadapter.h', - 'base/videobroadcaster.cc', - 'base/videobroadcaster.h', 'base/videocapturer.cc', 'base/videocapturer.h', 'base/videocapturerfactory.h', diff --git a/webrtc/media/webrtc/webrtcvideocapturer.cc b/webrtc/media/webrtc/webrtcvideocapturer.cc index 6d9a2914a0..c5eb1adadc 100644 --- a/webrtc/media/webrtc/webrtcvideocapturer.cc +++ b/webrtc/media/webrtc/webrtcvideocapturer.cc @@ -14,6 +14,7 @@ #include #endif +#ifdef HAVE_WEBRTC_VIDEO #include "webrtc/base/arraysize.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" @@ -202,6 +203,9 @@ bool WebRtcVideoCapturer::Init(const Device& device) { SetId(device.id); SetSupportedFormats(supported); + // Ensure these 2 have the same value. + SetApplyRotation(module_->GetApplyRotation()); + return true; } @@ -239,7 +243,7 @@ bool WebRtcVideoCapturer::GetBestCaptureFormat(const VideoFormat& desired, } return true; } -void WebRtcVideoCapturer::OnSinkWantsChanged(const rtc::VideoSinkWants& wants) { +bool WebRtcVideoCapturer::SetApplyRotation(bool enable) { // Can't take lock here as this will cause deadlock with // OnIncomingCapturedFrame. In fact, the whole method, including methods it // calls, can't take lock. @@ -249,14 +253,13 @@ void WebRtcVideoCapturer::OnSinkWantsChanged(const rtc::VideoSinkWants& wants) { webrtc::field_trial::FindFullName("WebRTC-CVO"); if (group_name == "Disabled") { - return; + return true; } - VideoCapturer::OnSinkWantsChanged(wants); - bool result = module_->SetApplyRotation(wants.rotation_applied); - RTC_CHECK(result); - - return; + if (!VideoCapturer::SetApplyRotation(enable)) { + return false; + } + return module_->SetApplyRotation(enable); } CaptureState WebRtcVideoCapturer::Start(const VideoFormat& capture_format) { @@ -424,3 +427,5 @@ WebRtcCapturedFrame::WebRtcCapturedFrame(const webrtc::VideoFrame& sample, } } // namespace cricket + +#endif // HAVE_WEBRTC_VIDEO diff --git a/webrtc/media/webrtc/webrtcvideocapturer.h b/webrtc/media/webrtc/webrtcvideocapturer.h index 0d5eb3d6df..ef4dea48a1 100644 --- a/webrtc/media/webrtc/webrtcvideocapturer.h +++ b/webrtc/media/webrtc/webrtcvideocapturer.h @@ -11,6 +11,8 @@ #ifndef WEBRTC_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURER_H_ #define WEBRTC_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURER_H_ +#ifdef HAVE_WEBRTC_VIDEO + #include #include @@ -48,15 +50,15 @@ class WebRtcVideoCapturer : public VideoCapturer, bool Init(webrtc::VideoCaptureModule* module); // Override virtual methods of the parent class VideoCapturer. - bool GetBestCaptureFormat(const VideoFormat& desired, - VideoFormat* best_format) override; - CaptureState Start(const VideoFormat& capture_format) override; - void Stop() override; - bool IsRunning() override; - bool IsScreencast() const override { return false; } + virtual bool GetBestCaptureFormat(const VideoFormat& desired, + VideoFormat* best_format); + virtual CaptureState Start(const VideoFormat& capture_format); + virtual void Stop(); + virtual bool IsRunning(); + virtual bool IsScreencast() const { return false; } + virtual bool SetApplyRotation(bool enable); protected: - void OnSinkWantsChanged(const rtc::VideoSinkWants& wants) override; // Override virtual methods of the parent class VideoCapturer. virtual bool GetPreferredFourccs(std::vector* fourccs); @@ -93,4 +95,5 @@ struct WebRtcCapturedFrame : public CapturedFrame { } // namespace cricket +#endif // HAVE_WEBRTC_VIDEO #endif // WEBRTC_MEDIA_WEBRTC_WEBRTCVIDEOCAPTURER_H_ diff --git a/webrtc/media/webrtc/webrtcvideoengine2.cc b/webrtc/media/webrtc/webrtcvideoengine2.cc index b968322ee3..c2b65ced27 100644 --- a/webrtc/media/webrtc/webrtcvideoengine2.cc +++ b/webrtc/media/webrtc/webrtcvideoengine2.cc @@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#ifdef HAVE_WEBRTC_VIDEO #include "webrtc/media/webrtc/webrtcvideoengine2.h" #include @@ -969,7 +970,7 @@ bool WebRtcVideoChannel2::SetVideoSend(uint32_t ssrc, bool enable, bool WebRtcVideoChannel2::ValidateSendSsrcAvailability( const StreamParams& sp) const { - for (uint32_t ssrc : sp.ssrcs) { + for (uint32_t ssrc: sp.ssrcs) { if (send_ssrcs_.find(ssrc) != send_ssrcs_.end()) { LOG(LS_ERROR) << "Send stream with SSRC '" << ssrc << "' already exists."; return false; @@ -980,7 +981,7 @@ bool WebRtcVideoChannel2::ValidateSendSsrcAvailability( bool WebRtcVideoChannel2::ValidateReceiveSsrcAvailability( const StreamParams& sp) const { - for (uint32_t ssrc : sp.ssrcs) { + for (uint32_t ssrc: sp.ssrcs) { if (receive_ssrcs_.find(ssrc) != receive_ssrcs_.end()) { LOG(LS_ERROR) << "Receive stream with SSRC '" << ssrc << "' already exists."; @@ -1286,6 +1287,11 @@ bool WebRtcVideoChannel2::SetCapturer(uint32_t ssrc, VideoCapturer* capturer) { return false; } } + + if (capturer) { + capturer->SetApplyRotation(!ContainsHeaderExtension( + send_rtp_extensions_, kRtpVideoRotationHeaderExtension)); + } { rtc::CritScope lock(&capturer_crit_); capturers_[ssrc] = capturer; @@ -1549,11 +1555,12 @@ static void CreateBlackFrame(webrtc::VideoFrame* video_frame, video_frame->allocated_size(webrtc::kVPlane)); } -void WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame( - const VideoFrame& frame) { - TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::OnFrame"); - webrtc::VideoFrame video_frame(frame.GetVideoFrameBuffer(), 0, 0, - frame.GetVideoRotation()); +void WebRtcVideoChannel2::WebRtcVideoSendStream::InputFrame( + VideoCapturer* capturer, + const VideoFrame* frame) { + TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::InputFrame"); + webrtc::VideoFrame video_frame(frame->GetVideoFrameBuffer(), 0, 0, + frame->GetVideoRotation()); rtc::CritScope cs(&lock_); if (stream_ == NULL) { // Frame input before send codecs are configured, dropping frame. @@ -1567,11 +1574,12 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame( if (muted_) { // Create a black frame to transmit instead. - CreateBlackFrame(&video_frame, static_cast(frame.GetWidth()), - static_cast(frame.GetHeight())); + CreateBlackFrame(&video_frame, + static_cast(frame->GetWidth()), + static_cast(frame->GetHeight())); } - int64_t frame_delta_ms = frame.GetTimeStamp() / rtc::kNumNanosecsPerMillisec; + int64_t frame_delta_ms = frame->GetTimeStamp() / rtc::kNumNanosecsPerMillisec; // frame->GetTimeStamp() is essentially a delta, align to webrtc time if (first_frame_timestamp_ms_ == 0) { first_frame_timestamp_ms_ = rtc::Time() - frame_delta_ms; @@ -1580,8 +1588,8 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame( last_frame_timestamp_ms_ = first_frame_timestamp_ms_ + frame_delta_ms; video_frame.set_render_time_ms(last_frame_timestamp_ms_); // Reconfigure codec if necessary. - SetDimensions(video_frame.width(), video_frame.height(), - capturer_->IsScreencast()); + SetDimensions( + video_frame.width(), video_frame.height(), capturer->IsScreencast()); stream_->Input()->IncomingCapturedFrame(video_frame); } @@ -1623,8 +1631,10 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer( } capturer_ = capturer; - capturer_->AddOrUpdateSink(this, sink_wants_); } + // Lock cannot be held while connecting the capturer to prevent lock-order + // violations. + capturer->SignalVideoFrame.connect(this, &WebRtcVideoSendStream::InputFrame); return true; } @@ -1646,8 +1656,7 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::DisconnectCapturer() { capturer = capturer_; capturer_ = NULL; } - capturer->RemoveSink(this); - + capturer->SignalVideoFrame.disconnect(this); return true; } @@ -1785,10 +1794,9 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters( } if (params.rtp_header_extensions) { parameters_.config.rtp.extensions = *params.rtp_header_extensions; - sink_wants_.rotation_applied = !ContainsHeaderExtension( - *params.rtp_header_extensions, kRtpVideoRotationHeaderExtension); if (capturer_) { - capturer_->AddOrUpdateSink(this, sink_wants_); + capturer_->SetApplyRotation(!ContainsHeaderExtension( + *params.rtp_header_extensions, kRtpVideoRotationHeaderExtension)); } recreate_stream = true; } @@ -2497,3 +2505,5 @@ WebRtcVideoChannel2::MapCodecs(const std::vector& codecs) { } } // namespace cricket + +#endif // HAVE_WEBRTC_VIDEO diff --git a/webrtc/media/webrtc/webrtcvideoengine2.h b/webrtc/media/webrtc/webrtcvideoengine2.h index affcaaffab..98bad0f007 100644 --- a/webrtc/media/webrtc/webrtcvideoengine2.h +++ b/webrtc/media/webrtc/webrtcvideoengine2.h @@ -12,7 +12,6 @@ #define WEBRTC_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_H_ #include -#include #include #include @@ -21,7 +20,6 @@ #include "webrtc/base/thread_annotations.h" #include "webrtc/base/thread_checker.h" #include "webrtc/media/base/videosinkinterface.h" -#include "webrtc/media/base/videosourceinterface.h" #include "webrtc/call.h" #include "webrtc/media/base/mediaengine.h" #include "webrtc/media/webrtc/webrtcvideochannelfactory.h" @@ -223,8 +221,7 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, // Wrapper for the sender part, this is where the capturer is connected and // frames are then converted from cricket frames to webrtc frames. - class WebRtcVideoSendStream - : public rtc::VideoSinkInterface { + class WebRtcVideoSendStream : public sigslot::has_slots<> { public: WebRtcVideoSendStream( webrtc::Call* call, @@ -236,13 +233,13 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, const rtc::Optional& codec_settings, const std::vector& rtp_extensions, const VideoSendParameters& send_params); - virtual ~WebRtcVideoSendStream(); + ~WebRtcVideoSendStream(); void SetOptions(const VideoOptions& options); // TODO(pbos): Move logic from SetOptions into this method. void SetSendParameters(const ChangedSendParameters& send_params); - void OnFrame(const cricket::VideoFrame& frame) override; + void InputFrame(VideoCapturer* capturer, const VideoFrame* frame); bool SetCapturer(VideoCapturer* capturer); void MuteStream(bool mute); bool DisconnectCapturer(); @@ -338,7 +335,6 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, const std::vector ssrcs_; const std::vector ssrc_groups_; webrtc::Call* const call_; - rtc::VideoSinkWants sink_wants_; WebRtcVideoEncoderFactory* const external_encoder_factory_ GUARDED_BY(lock_);