From 1829af6a390c4a53935b7227ce46831acbb53604 Mon Sep 17 00:00:00 2001 From: Tommi Date: Tue, 6 Feb 2018 09:29:17 +0100 Subject: [PATCH] Extend FakePeriodicVideoCapturer with FakeVideoCapturerWithTaskQueue. FakeVideoCapturerWithTaskQueue overrides frame related methods and delivers frame callbacks on a TaskQueue (separate thread), as is (must be) expected by the implementations being tested. I'm also moving the implementation out of the header and into a separate source file. In this CL, I'm updating one test to use the new class but more will follow. Bug: webrtc:8848 Change-Id: I5403c6bcc8b757e9d7fa9c368506667707b37b28 Reviewed-on: https://webrtc-review.googlesource.com/48360 Reviewed-by: Magnus Jedvert Commit-Queue: Tommi Cr-Commit-Position: refs/heads/master@{#21948} --- media/BUILD.gn | 5 + media/base/fakevideocapturer.cc | 176 +++++++++++++++++++++++++++ media/base/fakevideocapturer.h | 155 ++++++++--------------- pc/peerconnectionfactory_unittest.cc | 3 +- 4 files changed, 234 insertions(+), 105 deletions(-) create mode 100644 media/base/fakevideocapturer.cc diff --git a/media/BUILD.gn b/media/BUILD.gn index 371d2b1de9..d93c1610cc 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -69,7 +69,9 @@ rtc_static_library("rtc_media_base") { deps = [ "../api:audio_options_api", "../rtc_base:checks", + "../rtc_base:rtc_task_queue_api", "../rtc_base:sanitizer", + "../rtc_base:sequenced_task_checker", "../rtc_base:stringutils", ] sources = [ @@ -446,6 +448,7 @@ if (rtc_include_tests) { "../modules/video_coding:video_coding_utility", "../p2p:rtc_p2p", "../rtc_base:checks", + "../rtc_base:rtc_task_queue_api", "../rtc_base:stringutils", ] sources = [ @@ -453,6 +456,7 @@ if (rtc_include_tests) { "base/fakenetworkinterface.h", "base/fakertp.cc", "base/fakertp.h", + "base/fakevideocapturer.cc", "base/fakevideocapturer.h", "base/fakevideorenderer.h", "base/test/mock_mediachannel.h", @@ -542,6 +546,7 @@ if (rtc_include_tests) { "../pc:rtc_pc", "../pc:rtc_pc_base", "../rtc_base:checks", + "../rtc_base:rtc_task_queue_api", "../rtc_base:stringutils", "../test:field_trial", ] diff --git a/media/base/fakevideocapturer.cc b/media/base/fakevideocapturer.cc new file mode 100644 index 0000000000..a0d2df89ab --- /dev/null +++ b/media/base/fakevideocapturer.cc @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018 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 "media/base/fakevideocapturer.h" + +#include "rtc_base/arraysize.h" + +namespace cricket { + +FakeVideoCapturer::FakeVideoCapturer(bool is_screencast) + : running_(false), + initial_timestamp_(rtc::TimeNanos()), + next_timestamp_(rtc::kNumNanosecsPerMillisec), + is_screencast_(is_screencast), + rotation_(webrtc::kVideoRotation_0) { + // Default supported formats. Use ResetSupportedFormats to over write. + using cricket::VideoFormat; + static const VideoFormat formats[] = { + {1280, 720, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, + {640, 480, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, + {320, 240, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, + {160, 120, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, + {1280, 720, VideoFormat::FpsToInterval(60), cricket::FOURCC_I420}, + }; + ResetSupportedFormats({&formats[0], &formats[arraysize(formats)]}); +} + +FakeVideoCapturer::FakeVideoCapturer() : FakeVideoCapturer(false) {} + +FakeVideoCapturer::~FakeVideoCapturer() { + SignalDestroyed(this); +} + +void FakeVideoCapturer::ResetSupportedFormats( + const std::vector& formats) { + SetSupportedFormats(formats); +} + +bool FakeVideoCapturer::CaptureFrame() { + if (!GetCaptureFormat()) { + return false; + } + return CaptureCustomFrame( + GetCaptureFormat()->width, GetCaptureFormat()->height, + GetCaptureFormat()->interval, GetCaptureFormat()->fourcc); +} + +bool FakeVideoCapturer::CaptureCustomFrame(int width, + int height, + uint32_t fourcc) { + // Default to 30fps. + return CaptureCustomFrame(width, height, rtc::kNumNanosecsPerSec / 30, + fourcc); +} + +bool FakeVideoCapturer::CaptureCustomFrame(int width, + int height, + int64_t timestamp_interval, + uint32_t fourcc) { + if (!running_) { + return false; + } + RTC_CHECK(fourcc == FOURCC_I420); + RTC_CHECK(width > 0); + RTC_CHECK(height > 0); + + int adapted_width; + int adapted_height; + int crop_width; + int crop_height; + int crop_x; + int crop_y; + + // TODO(nisse): It's a bit silly to have this logic in a fake + // class. Child classes of VideoCapturer are expected to call + // AdaptFrame, and the test case + // VideoCapturerTest.SinkWantsMaxPixelAndMaxPixelCountStepUp + // depends on this. + if (AdaptFrame(width, height, next_timestamp_ / rtc::kNumNanosecsPerMicrosec, + next_timestamp_ / rtc::kNumNanosecsPerMicrosec, &adapted_width, + &adapted_height, &crop_width, &crop_height, &crop_x, &crop_y, + nullptr)) { + rtc::scoped_refptr buffer( + webrtc::I420Buffer::Create(adapted_width, adapted_height)); + buffer->InitializeData(); + + OnFrame(webrtc::VideoFrame(buffer, rotation_, + next_timestamp_ / rtc::kNumNanosecsPerMicrosec), + width, height); + } + next_timestamp_ += timestamp_interval; + + return true; +} + +cricket::CaptureState FakeVideoCapturer::Start( + const cricket::VideoFormat& format) { + SetCaptureFormat(&format); + running_ = true; + SetCaptureState(cricket::CS_RUNNING); + return cricket::CS_RUNNING; +} + +void FakeVideoCapturer::Stop() { + running_ = false; + SetCaptureFormat(NULL); + SetCaptureState(cricket::CS_STOPPED); +} + +bool FakeVideoCapturer::IsRunning() { + return running_; +} + +bool FakeVideoCapturer::IsScreencast() const { + return is_screencast_; +} + +bool FakeVideoCapturer::GetPreferredFourccs(std::vector* fourccs) { + fourccs->push_back(cricket::FOURCC_I420); + fourccs->push_back(cricket::FOURCC_MJPG); + return true; +} + +void FakeVideoCapturer::SetRotation(webrtc::VideoRotation rotation) { + rotation_ = rotation; +} + +webrtc::VideoRotation FakeVideoCapturer::GetRotation() { + return rotation_; +} + +FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue( + bool is_screencast) + : FakeVideoCapturer(is_screencast) {} + +FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue() {} + +bool FakeVideoCapturerWithTaskQueue::CaptureFrame() { + bool ret = false; + RunSynchronouslyOnTaskQueue( + [this, &ret]() { ret = FakeVideoCapturer::CaptureFrame(); }); + return ret; +} + +bool FakeVideoCapturerWithTaskQueue::CaptureCustomFrame(int width, + int height, + uint32_t fourcc) { + bool ret = false; + RunSynchronouslyOnTaskQueue([this, &ret, width, height, fourcc]() { + ret = FakeVideoCapturer::CaptureCustomFrame(width, height, fourcc); + }); + return ret; +} + +bool FakeVideoCapturerWithTaskQueue::CaptureCustomFrame( + int width, + int height, + int64_t timestamp_interval, + uint32_t fourcc) { + bool ret = false; + RunSynchronouslyOnTaskQueue( + [this, &ret, width, height, timestamp_interval, fourcc]() { + ret = FakeVideoCapturer::CaptureCustomFrame(width, height, + timestamp_interval, fourcc); + }); + return ret; +} + +} // namespace cricket diff --git a/media/base/fakevideocapturer.h b/media/base/fakevideocapturer.h index 536fe16356..3fe5ed7657 100644 --- a/media/base/fakevideocapturer.h +++ b/media/base/fakevideocapturer.h @@ -20,6 +20,8 @@ #include "api/video/video_frame.h" #include "media/base/videocapturer.h" #include "media/base/videocommon.h" +#include "rtc_base/event.h" +#include "rtc_base/task_queue.h" #include "rtc_base/timeutils.h" namespace cricket { @@ -27,117 +29,30 @@ namespace cricket { // Fake video capturer that allows the test to manually pump in frames. class FakeVideoCapturer : public cricket::VideoCapturer { public: - explicit FakeVideoCapturer(bool is_screencast) - : running_(false), - initial_timestamp_(rtc::TimeNanos()), - next_timestamp_(rtc::kNumNanosecsPerMillisec), - is_screencast_(is_screencast), - rotation_(webrtc::kVideoRotation_0) { - // Default supported formats. Use ResetSupportedFormats to over write. - std::vector formats; - formats.push_back(cricket::VideoFormat(1280, 720, - cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); - formats.push_back(cricket::VideoFormat(640, 480, - cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); - formats.push_back(cricket::VideoFormat(320, 240, - cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); - formats.push_back(cricket::VideoFormat(160, 120, - cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); - formats.push_back(cricket::VideoFormat(1280, 720, - cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_I420)); - ResetSupportedFormats(formats); - } - FakeVideoCapturer() : FakeVideoCapturer(false) {} + explicit FakeVideoCapturer(bool is_screencast); + FakeVideoCapturer(); - ~FakeVideoCapturer() { - SignalDestroyed(this); - } + ~FakeVideoCapturer() override; - void ResetSupportedFormats(const std::vector& formats) { - SetSupportedFormats(formats); - } - bool CaptureFrame() { - if (!GetCaptureFormat()) { - return false; - } - return CaptureCustomFrame(GetCaptureFormat()->width, - GetCaptureFormat()->height, - GetCaptureFormat()->interval, - GetCaptureFormat()->fourcc); - } - bool CaptureCustomFrame(int width, int height, uint32_t fourcc) { - // Default to 30fps. - return CaptureCustomFrame(width, height, rtc::kNumNanosecsPerSec / 30, - fourcc); - } - bool CaptureCustomFrame(int width, - int height, - int64_t timestamp_interval, - uint32_t fourcc) { - if (!running_) { - return false; - } - RTC_CHECK(fourcc == FOURCC_I420); - RTC_CHECK(width > 0); - RTC_CHECK(height > 0); - - int adapted_width; - int adapted_height; - int crop_width; - int crop_height; - int crop_x; - int crop_y; - - // TODO(nisse): It's a bit silly to have this logic in a fake - // class. Child classes of VideoCapturer are expected to call - // AdaptFrame, and the test case - // VideoCapturerTest.SinkWantsMaxPixelAndMaxPixelCountStepUp - // depends on this. - if (AdaptFrame(width, height, - next_timestamp_ / rtc::kNumNanosecsPerMicrosec, - next_timestamp_ / rtc::kNumNanosecsPerMicrosec, - &adapted_width, &adapted_height, &crop_width, &crop_height, - &crop_x, &crop_y, nullptr)) { - rtc::scoped_refptr buffer( - webrtc::I420Buffer::Create(adapted_width, adapted_height)); - buffer->InitializeData(); - - OnFrame(webrtc::VideoFrame( - buffer, rotation_, - next_timestamp_ / rtc::kNumNanosecsPerMicrosec), - width, height); - } - next_timestamp_ += timestamp_interval; - - return true; - } + void ResetSupportedFormats(const std::vector& formats); + virtual bool CaptureFrame(); + virtual bool CaptureCustomFrame(int width, int height, uint32_t fourcc); + virtual bool CaptureCustomFrame(int width, + int height, + int64_t timestamp_interval, + uint32_t fourcc); sigslot::signal1 SignalDestroyed; - cricket::CaptureState Start(const cricket::VideoFormat& format) override { - SetCaptureFormat(&format); - running_ = true; - SetCaptureState(cricket::CS_RUNNING); - return cricket::CS_RUNNING; - } - void Stop() override { - running_ = false; - SetCaptureFormat(NULL); - SetCaptureState(cricket::CS_STOPPED); - } - bool IsRunning() override { return running_; } - bool IsScreencast() const override { return is_screencast_; } - bool GetPreferredFourccs(std::vector* fourccs) override { - fourccs->push_back(cricket::FOURCC_I420); - fourccs->push_back(cricket::FOURCC_MJPG); - return true; - } + cricket::CaptureState Start(const cricket::VideoFormat& format) override; + void Stop() override; + bool IsRunning() override; + bool IsScreencast() const override; + bool GetPreferredFourccs(std::vector* fourccs) override; - void SetRotation(webrtc::VideoRotation rotation) { - rotation_ = rotation; - } + void SetRotation(webrtc::VideoRotation rotation); - webrtc::VideoRotation GetRotation() { return rotation_; } + webrtc::VideoRotation GetRotation(); private: bool running_; @@ -147,6 +62,38 @@ class FakeVideoCapturer : public cricket::VideoCapturer { webrtc::VideoRotation rotation_; }; +// Inherits from FakeVideoCapturer but adds a TaskQueue so that frames can be +// delivered on a TaskQueue as expected by VideoSinkInterface implementations. +class FakeVideoCapturerWithTaskQueue : public FakeVideoCapturer { + public: + explicit FakeVideoCapturerWithTaskQueue(bool is_screencast); + FakeVideoCapturerWithTaskQueue(); + + bool CaptureFrame() override; + bool CaptureCustomFrame(int width, int height, uint32_t fourcc) override; + bool CaptureCustomFrame(int width, + int height, + int64_t timestamp_interval, + uint32_t fourcc) override; + + protected: + template + void RunSynchronouslyOnTaskQueue(Closure&& closure) { + if (task_queue_.IsCurrent()) { + closure(); + return; + } + rtc::Event event(false, false); + task_queue_.PostTask([&closure, &event]() { + closure(); + event.Set(); + }); + event.Wait(rtc::Event::kForever); + } + + rtc::TaskQueue task_queue_{"FakeVideoCapturerWithTaskQueue"}; +}; + } // namespace cricket #endif // MEDIA_BASE_FAKEVIDEOCAPTURER_H_ diff --git a/pc/peerconnectionfactory_unittest.cc b/pc/peerconnectionfactory_unittest.cc index a1bdbf5af5..c8133a355a 100644 --- a/pc/peerconnectionfactory_unittest.cc +++ b/pc/peerconnectionfactory_unittest.cc @@ -341,7 +341,8 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) { // This test verifies the captured stream is rendered locally using a // local video track. TEST_F(PeerConnectionFactoryTest, LocalRendering) { - cricket::FakeVideoCapturer* capturer = new cricket::FakeVideoCapturer(); + cricket::FakeVideoCapturerWithTaskQueue* capturer = + new cricket::FakeVideoCapturerWithTaskQueue(); // The source takes ownership of |capturer|, but we keep a raw pointer to // inject fake frames. rtc::scoped_refptr source(