diff --git a/media/base/fakeframesource.cc b/media/base/fakeframesource.cc index f03dd837e8..ffc3eee773 100644 --- a/media/base/fakeframesource.cc +++ b/media/base/fakeframesource.cc @@ -11,6 +11,7 @@ #include "media/base/fakeframesource.h" #include "api/video/i420_buffer.h" +#include "rtc_base/checks.h" namespace cricket { @@ -21,7 +22,7 @@ FakeFrameSource::FakeFrameSource(int width, int height, int interval_us) RTC_CHECK_GT(interval_us_, 0); } -webrtc::VideoRotation FakeFrameSource::GetRotation() { +webrtc::VideoRotation FakeFrameSource::GetRotation() const { return rotation_; } @@ -29,12 +30,28 @@ void FakeFrameSource::SetRotation(webrtc::VideoRotation rotation) { rotation_ = rotation; } +webrtc::VideoFrame FakeFrameSource::GetFrameRotationApplied() { + switch (rotation_) { + case webrtc::kVideoRotation_0: + case webrtc::kVideoRotation_180: + return GetFrame(width_, height_, webrtc::kVideoRotation_0, interval_us_); + case webrtc::kVideoRotation_90: + case webrtc::kVideoRotation_270: + return GetFrame(height_, width_, webrtc::kVideoRotation_0, interval_us_); + } + RTC_NOTREACHED() << "Invalid rotation value: " << static_cast(rotation_); + // Without this return, the Windows Visual Studio compiler complains + // "not all control paths return a value". + return GetFrame(); +} + webrtc::VideoFrame FakeFrameSource::GetFrame() { - return GetFrame(width_, height_, interval_us_); + return GetFrame(width_, height_, rotation_, interval_us_); } webrtc::VideoFrame FakeFrameSource::GetFrame(int width, int height, + webrtc::VideoRotation rotation, int interval_us) { RTC_CHECK_GT(width, 0); RTC_CHECK_GT(height, 0); @@ -45,7 +62,7 @@ webrtc::VideoFrame FakeFrameSource::GetFrame(int width, buffer->InitializeData(); webrtc::VideoFrame frame = - webrtc::VideoFrame(buffer, rotation_, next_timestamp_us_); + webrtc::VideoFrame(buffer, rotation, next_timestamp_us_); next_timestamp_us_ += interval_us; return frame; diff --git a/media/base/fakeframesource.h b/media/base/fakeframesource.h index b9ac4a7157..db440457c0 100644 --- a/media/base/fakeframesource.h +++ b/media/base/fakeframesource.h @@ -21,12 +21,17 @@ class FakeFrameSource { public: FakeFrameSource(int width, int height, int interval_us); - webrtc::VideoRotation GetRotation(); + webrtc::VideoRotation GetRotation() const; void SetRotation(webrtc::VideoRotation rotation); webrtc::VideoFrame GetFrame(); - // Override default size and interval. - webrtc::VideoFrame GetFrame(int width, int height, int interval_us); + webrtc::VideoFrame GetFrameRotationApplied(); + + // Override configuration. + webrtc::VideoFrame GetFrame(int width, + int height, + webrtc::VideoRotation rotation, + int interval_us); private: const int width_; diff --git a/media/base/fakevideocapturer.cc b/media/base/fakevideocapturer.cc index 80021e571b..845ccebde6 100644 --- a/media/base/fakevideocapturer.cc +++ b/media/base/fakevideocapturer.cc @@ -53,8 +53,8 @@ bool FakeVideoCapturer::CaptureCustomFrame(int width, int height) { // Default to 30fps. // TODO(nisse): Would anything break if we always stick to // the configure frame interval? - return CaptureFrame( - frame_source_->GetFrame(width, height, rtc::kNumMicrosecsPerSec / 30)); + return CaptureFrame(frame_source_->GetFrame(width, height, rotation_, + rtc::kNumMicrosecsPerSec / 30)); } bool FakeVideoCapturer::CaptureFrame(const webrtc::VideoFrame& frame) { diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc index 969fc804e1..e5f3ad424a 100644 --- a/pc/peerconnection_integrationtest.cc +++ b/pc/peerconnection_integrationtest.cc @@ -48,7 +48,7 @@ #include "pc/rtpmediautils.h" #include "pc/sessiondescription.h" #include "pc/test/fakeaudiocapturemodule.h" -#include "pc/test/fakeperiodicvideocapturer.h" +#include "pc/test/fakeperiodicvideosource.h" #include "pc/test/fakertccertificategenerator.h" #include "pc/test/fakevideotrackrenderer.h" #include "pc/test/mockpeerconnectionobservers.h" @@ -238,6 +238,20 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, return client; } + ~PeerConnectionWrapper() { + // Tear down video sources in the proper order. + for (const auto& video_source : fake_video_sources_) { + // No more calls to downstream OnFrame + video_source->Stop(); + } + for (const auto& track_source : video_track_sources_) { + // No more calls to upstream AddOrUpdateSink + track_source->OnSourceDestroyed(); + } + fake_video_sources_.clear(); + video_track_sources_.clear(); + } + webrtc::PeerConnectionFactoryInterface* pc_factory() const { return peer_connection_factory_.get(); } @@ -325,18 +339,21 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, } rtc::scoped_refptr CreateLocalVideoTrack() { - return CreateLocalVideoTrackInternal(FakeConstraints(), - webrtc::kVideoRotation_0); + return CreateLocalVideoTrackInternal( + webrtc::FakePeriodicVideoSource::Config()); } rtc::scoped_refptr - CreateLocalVideoTrackWithConstraints(const FakeConstraints& constraints) { - return CreateLocalVideoTrackInternal(constraints, webrtc::kVideoRotation_0); + CreateLocalVideoTrackWithConfig( + webrtc::FakePeriodicVideoSource::Config config) { + return CreateLocalVideoTrackInternal(config); } rtc::scoped_refptr CreateLocalVideoTrackWithRotation(webrtc::VideoRotation rotation) { - return CreateLocalVideoTrackInternal(FakeConstraints(), rotation); + webrtc::FakePeriodicVideoSource::Config config; + config.rotation = rotation; + return CreateLocalVideoTrackInternal(config); } rtc::scoped_refptr AddTrack( @@ -679,23 +696,20 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, } rtc::scoped_refptr CreateLocalVideoTrackInternal( - const FakeConstraints& constraints, - webrtc::VideoRotation rotation) { + webrtc::FakePeriodicVideoSource::Config config) { // Set max frame rate to 10fps to reduce the risk of test flakiness. // TODO(deadbeef): Do something more robust. - FakeConstraints source_constraints = constraints; - source_constraints.SetMandatoryMaxFrameRate(10); + config.frame_interval_ms = 100; - cricket::FakeVideoCapturer* fake_capturer = - new webrtc::FakePeriodicVideoCapturer(); - fake_capturer->SetRotation(rotation); - video_capturers_.push_back(fake_capturer); - rtc::scoped_refptr source = - peer_connection_factory_->CreateVideoSource(fake_capturer, - &source_constraints); + fake_video_sources_.emplace_back( + rtc::MakeUnique(config)); + + video_track_sources_.emplace_back( + new rtc::RefCountedObject( + fake_video_sources_.back().get(), false /* remote */)); rtc::scoped_refptr track( - peer_connection_factory_->CreateVideoTrack(rtc::CreateRandomUuid(), - source)); + peer_connection_factory_->CreateVideoTrack( + rtc::CreateRandomUuid(), video_track_sources_.back())); if (!local_video_renderer_) { local_video_renderer_.reset(new webrtc::FakeVideoTrackRenderer(track)); } @@ -975,9 +989,12 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, int signaling_delay_ms_ = 0; bool signal_ice_candidates_ = true; - // Store references to the video capturers we've created, so that we can stop + // Store references to the video sources we've created, so that we can stop // them, if required. - std::vector video_capturers_; + std::vector> + fake_video_sources_; + std::vector> + video_track_sources_; // |local_video_renderer_| attached to the first created local video track. std::unique_ptr local_video_renderer_; @@ -1750,35 +1767,6 @@ TEST_P(PeerConnectionIntegrationTest, remote_cert->ToPEMString()); } -// This test sets up a call between two parties (using DTLS) and tests that we -// can get a video aspect ratio of 16:9. -TEST_P(PeerConnectionIntegrationTest, SendAndReceive16To9AspectRatio) { - ASSERT_TRUE(CreatePeerConnectionWrappers()); - ConnectFakeSignaling(); - - // Add video tracks with 16:9 constraint. - FakeConstraints constraints; - double requested_ratio = 16.0 / 9; - constraints.SetMandatoryMinAspectRatio(requested_ratio); - caller()->AddTrack( - caller()->CreateLocalVideoTrackWithConstraints(constraints)); - callee()->AddTrack( - callee()->CreateLocalVideoTrackWithConstraints(constraints)); - - // Do normal offer/answer and wait for at least one frame to be received in - // each direction. - caller()->CreateAndSetAndSignalOffer(); - ASSERT_TRUE_WAIT(caller()->min_video_frames_received_per_track() > 0 && - callee()->min_video_frames_received_per_track() > 0, - kMaxWaitForFramesMs); - - // Check rendered aspect ratio. - EXPECT_EQ(requested_ratio, caller()->local_rendered_aspect_ratio()); - EXPECT_EQ(requested_ratio, caller()->rendered_aspect_ratio()); - EXPECT_EQ(requested_ratio, callee()->local_rendered_aspect_ratio()); - EXPECT_EQ(requested_ratio, callee()->rendered_aspect_ratio()); -} - // This test sets up a call between two parties with a source resolution of // 1280x720 and verifies that a 16:9 aspect ratio is received. TEST_P(PeerConnectionIntegrationTest, @@ -1786,15 +1774,12 @@ TEST_P(PeerConnectionIntegrationTest, ASSERT_TRUE(CreatePeerConnectionWrappers()); ConnectFakeSignaling(); - // Similar to above test, but uses MandatoryMin[Width/Height] constraint - // instead of aspect ratio constraint. - FakeConstraints constraints; - constraints.SetMandatoryMinWidth(1280); - constraints.SetMandatoryMinHeight(720); - caller()->AddTrack( - caller()->CreateLocalVideoTrackWithConstraints(constraints)); - callee()->AddTrack( - callee()->CreateLocalVideoTrackWithConstraints(constraints)); + // Add video tracks with 16:9 aspect ratio, size 1280 x 720. + webrtc::FakePeriodicVideoSource::Config config; + config.width = 1280; + config.height = 720; + caller()->AddTrack(caller()->CreateLocalVideoTrackWithConfig(config)); + callee()->AddTrack(callee()->CreateLocalVideoTrackWithConfig(config)); // Do normal offer/answer and wait for at least one frame to be received in // each direction. diff --git a/pc/test/fakeperiodicvideosource.h b/pc/test/fakeperiodicvideosource.h index fd5a3da308..62076350db 100644 --- a/pc/test/fakeperiodicvideosource.h +++ b/pc/test/fakeperiodicvideosource.h @@ -24,15 +24,23 @@ namespace webrtc { class FakePeriodicVideoSource final : public rtc::VideoSourceInterface { public: - static constexpr int kFrameIntervalMs = 33; - static constexpr int kWidth = 640; - static constexpr int kHeight = 480; + static constexpr int kDefaultFrameIntervalMs = 33; + static constexpr int kDefaultWidth = 640; + static constexpr int kDefaultHeight = 480; - FakePeriodicVideoSource() + struct Config { + int width = kDefaultWidth; + int height = kDefaultHeight; + int frame_interval_ms = kDefaultFrameIntervalMs; + VideoRotation rotation = kVideoRotation_0; + }; + + FakePeriodicVideoSource() : FakePeriodicVideoSource(Config()) {} + explicit FakePeriodicVideoSource(Config config) : task_queue_( rtc::MakeUnique("FakePeriodicVideoTrackSource")) { thread_checker_.DetachFromThread(); - task_queue_->PostTask(rtc::MakeUnique(&broadcaster_)); + task_queue_->PostTask(rtc::MakeUnique(config, &broadcaster_)); } void RemoveSink(rtc::VideoSinkInterface* sink) override { @@ -54,23 +62,32 @@ class FakePeriodicVideoSource final private: class FrameTask : public rtc::QueuedTask { public: - explicit FrameTask(rtc::VideoSinkInterface* sink) - : frame_source_(kWidth, - kHeight, - kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec), - sink_(sink) {} + FrameTask(Config config, rtc::VideoBroadcaster* broadcaster) + : frame_interval_ms_(config.frame_interval_ms), + frame_source_( + config.width, + config.height, + config.frame_interval_ms * rtc::kNumMicrosecsPerMillisec), + broadcaster_(broadcaster) { + frame_source_.SetRotation(config.rotation); + } bool Run() override { - sink_->OnFrame(frame_source_.GetFrame()); + if (broadcaster_->wants().rotation_applied) { + broadcaster_->OnFrame(frame_source_.GetFrameRotationApplied()); + } else { + broadcaster_->OnFrame(frame_source_.GetFrame()); + } + rtc::TaskQueue::Current()->PostDelayedTask(rtc::WrapUnique(this), - kFrameIntervalMs); + frame_interval_ms_); return false; } + int frame_interval_ms_; cricket::FakeFrameSource frame_source_; - rtc::VideoSinkInterface* sink_; + rtc::VideoBroadcaster* broadcaster_; }; - void OnFrame(const webrtc::VideoFrame& frame) { broadcaster_.OnFrame(frame); } rtc::ThreadChecker thread_checker_; rtc::VideoBroadcaster broadcaster_;