Enable capturing from camera in PC framework

Bug: webrtc:10138
Change-Id: Idcf10331b9f5208010b2bd29324e0fc1341db2d3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156241
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29431}
This commit is contained in:
Artem Titov
2019-10-10 13:29:03 +02:00
committed by Commit Bot
parent 16999814e6
commit 9afdddfed0
9 changed files with 184 additions and 75 deletions

View File

@ -167,16 +167,22 @@ class PeerConnectionE2EQualityTestFixture {
// Have to be unique among all specified configs for all peers in the call. // Have to be unique among all specified configs for all peers in the call.
// Will be auto generated if omitted. // Will be auto generated if omitted.
absl::optional<std::string> stream_label; absl::optional<std::string> stream_label;
// Only 1 from |generator|, |input_file_name| and |screen_share_config| can // Only 1 from |generator|, |input_file_name|, |screen_share_config| and
// be specified. If none of them are specified, then |generator| will be set // |capturing_device_index| can be specified. If none of them are specified,
// to VideoGeneratorType::kDefault. // then |generator| will be set to VideoGeneratorType::kDefault. If
// If specified generator of this type will be used to produce input video. // specified generator of this type will be used to produce input video.
absl::optional<VideoGeneratorType> generator; absl::optional<VideoGeneratorType> generator;
// If specified this file will be used as input. Input video will be played // If specified this file will be used as input. Input video will be played
// in a circle. // in a circle.
absl::optional<std::string> input_file_name; absl::optional<std::string> input_file_name;
// If specified screen share video stream will be created as input. // If specified screen share video stream will be created as input.
absl::optional<ScreenShareConfig> screen_share_config; absl::optional<ScreenShareConfig> screen_share_config;
// If specified this capturing device will be used to get input video. The
// |capturing_device_index| is the index of required capturing device in OS
// provided list of video devices. On Linux and Windows the list will be
// obtained via webrtc::VideoCaptureModule::DeviceInfo, on Mac OS via
// [RTCCameraVideoCapturer captureDevices].
absl::optional<size_t> capturing_device_index;
// If presented video will be transfered in simulcast/SVC mode depending on // If presented video will be transfered in simulcast/SVC mode depending on
// which encoder is used. // which encoder is used.
// //

View File

@ -275,6 +275,8 @@ if (rtc_include_tests) {
":test_peer", ":test_peer",
":video_quality_analyzer_injection_helper", ":video_quality_analyzer_injection_helper",
"../..:field_trial", "../..:field_trial",
"../..:platform_video_capturer",
"../..:video_test_common",
"../../../api:audio_quality_analyzer_api", "../../../api:audio_quality_analyzer_api",
"../../../api:libjingle_peerconnection_api", "../../../api:libjingle_peerconnection_api",
"../../../api:media_stream_interface", "../../../api:media_stream_interface",

View File

@ -159,7 +159,8 @@ void DefaultVideoQualityAnalyzer::OnFramePreEncode(
const webrtc::VideoFrame& frame) { const webrtc::VideoFrame& frame) {
rtc::CritScope crit(&lock_); rtc::CritScope crit(&lock_);
auto it = frame_stats_.find(frame.id()); auto it = frame_stats_.find(frame.id());
RTC_DCHECK(it != frame_stats_.end()); RTC_DCHECK(it != frame_stats_.end())
<< "Frame id=" << frame.id() << " not found";
frame_counters_.pre_encoded++; frame_counters_.pre_encoded++;
stream_frame_counters_[it->second.stream_label].pre_encoded++; stream_frame_counters_[it->second.stream_label].pre_encoded++;
it->second.pre_encode_time = Now(); it->second.pre_encode_time = Now();

View File

@ -11,6 +11,7 @@
#include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h" #include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h"
#include <utility> #include <utility>
#include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h" #include "test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.h"
@ -38,6 +39,37 @@ class VideoWriter final : public rtc::VideoSinkInterface<VideoFrame> {
test::VideoFrameWriter* video_writer_; test::VideoFrameWriter* video_writer_;
}; };
class AnalyzingFramePreprocessor
: public test::TestVideoCapturer::FramePreprocessor {
public:
AnalyzingFramePreprocessor(
std::string stream_label,
VideoQualityAnalyzerInterface* analyzer,
std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks)
: stream_label_(std::move(stream_label)),
analyzer_(analyzer),
sinks_(std::move(sinks)) {}
~AnalyzingFramePreprocessor() override = default;
VideoFrame Preprocess(const VideoFrame& source_frame) override {
// Copy VideoFrame to be able to set id on it.
VideoFrame frame = source_frame;
uint16_t frame_id = analyzer_->OnFrameCaptured(stream_label_, frame);
frame.set_id(frame_id);
for (auto& sink : sinks_) {
sink->OnFrame(frame);
}
return frame;
}
private:
const std::string stream_label_;
VideoQualityAnalyzerInterface* const analyzer_;
const std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>
sinks_;
};
// Intercepts generated frames and passes them also to video quality analyzer // Intercepts generated frames and passes them also to video quality analyzer
// and to provided sinks. // and to provided sinks.
class AnalyzingFrameGenerator final : public test::FrameGenerator { class AnalyzingFrameGenerator final : public test::FrameGenerator {
@ -142,10 +174,9 @@ VideoQualityAnalyzerInjectionHelper::WrapVideoDecoderFactory(
analyzer_.get()); analyzer_.get());
} }
std::unique_ptr<test::FrameGenerator> std::unique_ptr<test::TestVideoCapturer::FramePreprocessor>
VideoQualityAnalyzerInjectionHelper::WrapFrameGenerator( VideoQualityAnalyzerInjectionHelper::CreateFramePreprocessor(
const VideoConfig& config, const VideoConfig& config,
std::unique_ptr<test::FrameGenerator> delegate,
test::VideoFrameWriter* writer) const { test::VideoFrameWriter* writer) const {
std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks; std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
if (writer) { if (writer) {
@ -156,9 +187,8 @@ VideoQualityAnalyzerInjectionHelper::WrapFrameGenerator(
test::VideoRenderer::Create((*config.stream_label + "-capture").c_str(), test::VideoRenderer::Create((*config.stream_label + "-capture").c_str(),
config.width, config.height))); config.width, config.height)));
} }
return std::make_unique<AnalyzingFrameGenerator>( return std::make_unique<AnalyzingFramePreprocessor>(
std::move(*config.stream_label), std::move(delegate), analyzer_.get(), std::move(*config.stream_label), analyzer_.get(), std::move(sinks));
std::move(sinks));
} }
std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>

View File

@ -25,6 +25,7 @@
#include "test/frame_generator.h" #include "test/frame_generator.h"
#include "test/pc/e2e/analyzer/video/encoded_image_data_injector.h" #include "test/pc/e2e/analyzer/video/encoded_image_data_injector.h"
#include "test/pc/e2e/analyzer/video/id_generator.h" #include "test/pc/e2e/analyzer/video/id_generator.h"
#include "test/test_video_capturer.h"
#include "test/testsupport/video_frame_writer.h" #include "test/testsupport/video_frame_writer.h"
namespace webrtc { namespace webrtc {
@ -54,16 +55,15 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface {
std::unique_ptr<VideoDecoderFactory> WrapVideoDecoderFactory( std::unique_ptr<VideoDecoderFactory> WrapVideoDecoderFactory(
std::unique_ptr<VideoDecoderFactory> delegate) const; std::unique_ptr<VideoDecoderFactory> delegate) const;
// Wraps frame generator, so video quality analyzer will gain access to the // Creates VideoFrame preprocessor, that will allow video quality analyzer to
// captured frames. If |writer| in not nullptr, will dump captured frames // get access to the captured frames. If |writer| in not nullptr, will dump
// with provided writer. // captured frames with provided writer.
std::unique_ptr<test::FrameGenerator> WrapFrameGenerator( std::unique_ptr<test::TestVideoCapturer::FramePreprocessor>
const VideoConfig& config, CreateFramePreprocessor(const VideoConfig& config,
std::unique_ptr<test::FrameGenerator> delegate, test::VideoFrameWriter* writer) const;
test::VideoFrameWriter* writer) const; // Creates sink, that will allow video quality analyzer to get access to
// Creates sink, that will allow video quality analyzer to get access to the // the rendered frames. If |writer| in not nullptr, will dump rendered
// rendered frames. If |writer| in not nullptr, will dump rendered frames // frames with provided writer.
// with provided writer.
std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> CreateVideoSink( std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> CreateVideoSink(
const VideoConfig& config, const VideoConfig& config,
test::VideoFrameWriter* writer) const; test::VideoFrameWriter* writer) const;

View File

@ -30,9 +30,11 @@
#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_conversions.h"
#include "system_wrappers/include/cpu_info.h" #include "system_wrappers/include/cpu_info.h"
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
#include "test/frame_generator_capturer.h"
#include "test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h" #include "test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h"
#include "test/pc/e2e/analyzer/video/default_video_quality_analyzer.h" #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer.h"
#include "test/pc/e2e/stats_poller.h" #include "test/pc/e2e/stats_poller.h"
#include "test/platform_video_capturer.h"
#include "test/testsupport/file_utils.h" #include "test/testsupport/file_utils.h"
namespace webrtc { namespace webrtc {
@ -67,7 +69,9 @@ std::string VideoConfigSourcePresenceToString(const VideoConfig& video_config) {
<< "; video_config.input_file_name=" << "; video_config.input_file_name="
<< video_config.input_file_name.has_value() << video_config.input_file_name.has_value()
<< "; video_config.screen_share_config=" << "; video_config.screen_share_config="
<< video_config.screen_share_config.has_value() << ";"; << video_config.screen_share_config.has_value()
<< "; video_config.capturing_device_index="
<< video_config.capturing_device_index.has_value() << ";";
return builder.str(); return builder.str();
} }
@ -420,7 +424,7 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) {
// Audio dumps. // Audio dumps.
RTC_CHECK(!alice_); RTC_CHECK(!alice_);
RTC_CHECK(!bob_); RTC_CHECK(!bob_);
// Ensuring that FrameGeneratorCapturerVideoTrackSource and VideoFrameWriter // Ensuring that TestVideoCapturerVideoTrackSource and VideoFrameWriter
// are destroyed on the right thread. // are destroyed on the right thread.
RTC_CHECK(alice_video_sources_.empty()); RTC_CHECK(alice_video_sources_.empty());
RTC_CHECK(bob_video_sources_.empty()); RTC_CHECK(bob_video_sources_.empty());
@ -436,7 +440,8 @@ void PeerConnectionE2EQualityTest::SetDefaultValuesForMissingParams(
for (auto* p : params) { for (auto* p : params) {
for (auto& video_config : p->video_configs) { for (auto& video_config : p->video_configs) {
if (!video_config.generator && !video_config.input_file_name && if (!video_config.generator && !video_config.input_file_name &&
!video_config.screen_share_config) { !video_config.screen_share_config &&
!video_config.capturing_device_index) {
video_config.generator = VideoGeneratorType::kDefault; video_config.generator = VideoGeneratorType::kDefault;
} }
if (!video_config.stream_label) { if (!video_config.stream_label) {
@ -485,15 +490,16 @@ void PeerConnectionE2EQualityTest::ValidateParams(const RunParams& run_params,
video_labels.insert(video_config.stream_label.value()).second; video_labels.insert(video_config.stream_label.value()).second;
RTC_CHECK(inserted) << "Duplicate video_config.stream_label=" RTC_CHECK(inserted) << "Duplicate video_config.stream_label="
<< video_config.stream_label.value(); << video_config.stream_label.value();
RTC_CHECK(video_config.generator || video_config.input_file_name || int input_sources_count = 0;
video_config.screen_share_config) if (video_config.generator)
<< VideoConfigSourcePresenceToString(video_config); ++input_sources_count;
RTC_CHECK(!(video_config.input_file_name && video_config.generator)) if (video_config.input_file_name)
<< VideoConfigSourcePresenceToString(video_config); ++input_sources_count;
RTC_CHECK( if (video_config.screen_share_config)
!(video_config.input_file_name && video_config.screen_share_config)) ++input_sources_count;
<< VideoConfigSourcePresenceToString(video_config); if (video_config.capturing_device_index)
RTC_CHECK(!(video_config.screen_share_config && video_config.generator)) ++input_sources_count;
RTC_CHECK_EQ(input_sources_count, 1)
<< VideoConfigSourcePresenceToString(video_config); << VideoConfigSourcePresenceToString(video_config);
if (video_config.screen_share_config) { if (video_config.screen_share_config) {
@ -680,37 +686,27 @@ void PeerConnectionE2EQualityTest::TearDownCallOnSignalingThread() {
TearDownCall(); TearDownCall();
} }
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
PeerConnectionE2EQualityTest::MaybeAddMedia(TestPeer* peer) { PeerConnectionE2EQualityTest::MaybeAddMedia(TestPeer* peer) {
MaybeAddAudio(peer); MaybeAddAudio(peer);
return MaybeAddVideo(peer); return MaybeAddVideo(peer);
} }
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
PeerConnectionE2EQualityTest::MaybeAddVideo(TestPeer* peer) { PeerConnectionE2EQualityTest::MaybeAddVideo(TestPeer* peer) {
// Params here valid because of pre-run validation. // Params here valid because of pre-run validation.
Params* params = peer->params(); Params* params = peer->params();
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> out; std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>> out;
for (auto video_config : params->video_configs) { for (auto video_config : params->video_configs) {
// Create video generator. // Setup input video source into peer connection.
std::unique_ptr<test::FrameGenerator> frame_generator =
CreateFrameGenerator(video_config);
// Wrap it to inject video quality analyzer and enable dump of input video
// if required.
test::VideoFrameWriter* writer = test::VideoFrameWriter* writer =
MaybeCreateVideoWriter(video_config.input_dump_file_name, video_config); MaybeCreateVideoWriter(video_config.input_dump_file_name, video_config);
frame_generator = std::unique_ptr<test::TestVideoCapturer> capturer = CreateVideoCapturer(
video_quality_analyzer_injection_helper_->WrapFrameGenerator( video_config,
video_config, std::move(frame_generator), writer); video_quality_analyzer_injection_helper_->CreateFramePreprocessor(
video_config, writer));
// Setup FrameGenerator into peer connection. rtc::scoped_refptr<TestVideoCapturerVideoTrackSource> source =
auto capturer = std::make_unique<test::FrameGeneratorCapturer>( new rtc::RefCountedObject<TestVideoCapturerVideoTrackSource>(
clock_, std::move(frame_generator), video_config.fps,
*task_queue_factory_);
capturer->Init();
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource> source =
new rtc::RefCountedObject<FrameGeneratorCapturerVideoTrackSource>(
std::move(capturer), std::move(capturer),
/*is_screencast=*/video_config.screen_share_config && /*is_screencast=*/video_config.screen_share_config &&
video_config.screen_share_config->use_text_content_hint); video_config.screen_share_config->use_text_content_hint);
@ -740,9 +736,24 @@ PeerConnectionE2EQualityTest::MaybeAddVideo(TestPeer* peer) {
return out; return out;
} }
std::unique_ptr<test::FrameGenerator> std::unique_ptr<test::TestVideoCapturer>
PeerConnectionE2EQualityTest::CreateFrameGenerator( PeerConnectionE2EQualityTest::CreateVideoCapturer(
const VideoConfig& video_config) { const VideoConfig& video_config,
std::unique_ptr<test::TestVideoCapturer::FramePreprocessor>
frame_preprocessor) {
if (video_config.capturing_device_index) {
std::unique_ptr<test::TestVideoCapturer> capturer =
test::CreateVideoCapturer(video_config.width, video_config.height,
video_config.fps,
*video_config.capturing_device_index);
capturer->SetFramePreprocessor(std::move(frame_preprocessor));
RTC_CHECK(capturer)
<< "Failed to obtain input stream from capturing device #"
<< *video_config.capturing_device_index;
return capturer;
}
std::unique_ptr<test::FrameGenerator> frame_generator = nullptr;
if (video_config.generator) { if (video_config.generator) {
absl::optional<test::FrameGenerator::OutputType> frame_generator_type = absl::optional<test::FrameGenerator::OutputType> frame_generator_type =
absl::nullopt; absl::nullopt;
@ -753,22 +764,28 @@ PeerConnectionE2EQualityTest::CreateFrameGenerator(
} else if (video_config.generator == VideoGeneratorType::kI010) { } else if (video_config.generator == VideoGeneratorType::kI010) {
frame_generator_type = test::FrameGenerator::OutputType::kI010; frame_generator_type = test::FrameGenerator::OutputType::kI010;
} }
return test::FrameGenerator::CreateSquareGenerator( frame_generator = test::FrameGenerator::CreateSquareGenerator(
static_cast<int>(video_config.width), static_cast<int>(video_config.width),
static_cast<int>(video_config.height), frame_generator_type, static_cast<int>(video_config.height), frame_generator_type,
absl::nullopt); absl::nullopt);
} }
if (video_config.input_file_name) { if (video_config.input_file_name) {
return test::FrameGenerator::CreateFromYuvFile( frame_generator = test::FrameGenerator::CreateFromYuvFile(
std::vector<std::string>(/*count=*/1, std::vector<std::string>(/*count=*/1,
video_config.input_file_name.value()), video_config.input_file_name.value()),
video_config.width, video_config.height, /*frame_repeat_count=*/1); video_config.width, video_config.height, /*frame_repeat_count=*/1);
} }
if (video_config.screen_share_config) { if (video_config.screen_share_config) {
return CreateScreenShareFrameGenerator(video_config); frame_generator = CreateScreenShareFrameGenerator(video_config);
} }
RTC_NOTREACHED() << "Unsupported video_config input source"; RTC_CHECK(frame_generator) << "Unsupported video_config input source";
return nullptr;
auto capturer = std::make_unique<test::FrameGeneratorCapturer>(
clock_, std::move(frame_generator), video_config.fps,
*task_queue_factory_);
capturer->SetFramePreprocessor(std::move(frame_preprocessor));
capturer->Init();
return capturer;
} }
std::unique_ptr<test::FrameGenerator> std::unique_ptr<test::FrameGenerator>
@ -957,8 +974,8 @@ void PeerConnectionE2EQualityTest::ExchangeIceCandidates(
} }
void PeerConnectionE2EQualityTest::StartVideo( void PeerConnectionE2EQualityTest::StartVideo(
const std::vector< const std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>&
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources) { sources) {
for (auto& source : sources) { for (auto& source : sources) {
if (source->state() != MediaSourceInterface::SourceState::kLive) { if (source->state() != MediaSourceInterface::SourceState::kLive) {
source->Start(); source->Start();

View File

@ -20,7 +20,7 @@
#include "api/test/peerconnection_quality_test_fixture.h" #include "api/test/peerconnection_quality_test_fixture.h"
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include "pc/test/frame_generator_capturer_video_track_source.h" #include "pc/video_track_source.h"
#include "rtc_base/task_queue_for_test.h" #include "rtc_base/task_queue_for_test.h"
#include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/task_utils/repeating_task.h"
#include "rtc_base/thread.h" #include "rtc_base/thread.h"
@ -159,6 +159,33 @@ class PeerConfigurerImpl final
std::unique_ptr<Params> params_; std::unique_ptr<Params> params_;
}; };
class TestVideoCapturerVideoTrackSource : public VideoTrackSource {
public:
TestVideoCapturerVideoTrackSource(
std::unique_ptr<test::TestVideoCapturer> video_capturer,
bool is_screencast)
: VideoTrackSource(/*remote=*/false),
video_capturer_(std::move(video_capturer)),
is_screencast_(is_screencast) {}
~TestVideoCapturerVideoTrackSource() = default;
void Start() { SetState(kLive); }
void Stop() { SetState(kMuted); }
bool is_screencast() const override { return is_screencast_; }
protected:
rtc::VideoSourceInterface<VideoFrame>* source() override {
return video_capturer_.get();
}
private:
std::unique_ptr<test::TestVideoCapturer> video_capturer_;
const bool is_screencast_;
};
class PeerConnectionE2EQualityTest class PeerConnectionE2EQualityTest
: public PeerConnectionE2EQualityTestFixture { : public PeerConnectionE2EQualityTestFixture {
public: public:
@ -230,12 +257,14 @@ class PeerConnectionE2EQualityTest
// Have to be run on the signaling thread. // Have to be run on the signaling thread.
void SetupCallOnSignalingThread(const RunParams& run_params); void SetupCallOnSignalingThread(const RunParams& run_params);
void TearDownCallOnSignalingThread(); void TearDownCallOnSignalingThread();
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
MaybeAddMedia(TestPeer* peer); MaybeAddMedia(TestPeer* peer);
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
MaybeAddVideo(TestPeer* peer); MaybeAddVideo(TestPeer* peer);
std::unique_ptr<test::FrameGenerator> CreateFrameGenerator( std::unique_ptr<test::TestVideoCapturer> CreateVideoCapturer(
const VideoConfig& video_config); const VideoConfig& video_config,
std::unique_ptr<test::TestVideoCapturer::FramePreprocessor>
frame_preprocessor);
std::unique_ptr<test::FrameGenerator> CreateScreenShareFrameGenerator( std::unique_ptr<test::FrameGenerator> CreateScreenShareFrameGenerator(
const VideoConfig& video_config); const VideoConfig& video_config);
void MaybeAddAudio(TestPeer* peer); void MaybeAddAudio(TestPeer* peer);
@ -244,8 +273,8 @@ class PeerConnectionE2EQualityTest
void ExchangeOfferAnswer(SignalingInterceptor* signaling_interceptor); void ExchangeOfferAnswer(SignalingInterceptor* signaling_interceptor);
void ExchangeIceCandidates(SignalingInterceptor* signaling_interceptor); void ExchangeIceCandidates(SignalingInterceptor* signaling_interceptor);
void StartVideo( void StartVideo(
const std::vector< const std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>&
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources); sources);
void TearDownCall(); void TearDownCall();
test::VideoFrameWriter* MaybeCreateVideoWriter( test::VideoFrameWriter* MaybeCreateVideoWriter(
absl::optional<std::string> file_name, absl::optional<std::string> file_name,
@ -270,9 +299,9 @@ class PeerConnectionE2EQualityTest
std::vector<std::unique_ptr<QualityMetricsReporter>> std::vector<std::unique_ptr<QualityMetricsReporter>>
quality_metrics_reporters_; quality_metrics_reporters_;
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
alice_video_sources_; alice_video_sources_;
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>>
bob_video_sources_; bob_video_sources_;
std::vector<std::unique_ptr<test::VideoFrameWriter>> video_writers_; std::vector<std::unique_ptr<test::VideoFrameWriter>> video_writers_;
std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>

View File

@ -19,15 +19,16 @@
namespace webrtc { namespace webrtc {
namespace test { namespace test {
TestVideoCapturer::TestVideoCapturer() = default;
TestVideoCapturer::~TestVideoCapturer() = default; TestVideoCapturer::~TestVideoCapturer() = default;
void TestVideoCapturer::OnFrame(const VideoFrame& frame) { void TestVideoCapturer::OnFrame(const VideoFrame& original_frame) {
int cropped_width = 0; int cropped_width = 0;
int cropped_height = 0; int cropped_height = 0;
int out_width = 0; int out_width = 0;
int out_height = 0; int out_height = 0;
VideoFrame frame = MaybePreprocess(original_frame);
if (!video_adapter_.AdaptFrameResolution( if (!video_adapter_.AdaptFrameResolution(
frame.width(), frame.height(), frame.timestamp_us() * 1000, frame.width(), frame.height(), frame.timestamp_us() * 1000,
&cropped_width, &cropped_height, &out_width, &out_height)) { &cropped_width, &cropped_height, &out_width, &out_height)) {
@ -75,5 +76,14 @@ void TestVideoCapturer::UpdateVideoAdapter() {
wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps); wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps);
} }
VideoFrame TestVideoCapturer::MaybePreprocess(const VideoFrame& frame) {
rtc::CritScope crit(&lock_);
if (preprocessor_ != nullptr) {
return preprocessor_->Preprocess(frame);
} else {
return frame;
}
}
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -18,18 +18,29 @@
#include "api/video/video_source_interface.h" #include "api/video/video_source_interface.h"
#include "media/base/video_adapter.h" #include "media/base/video_adapter.h"
#include "media/base/video_broadcaster.h" #include "media/base/video_broadcaster.h"
#include "rtc_base/critical_section.h"
namespace webrtc { namespace webrtc {
namespace test { namespace test {
class TestVideoCapturer : public rtc::VideoSourceInterface<VideoFrame> { class TestVideoCapturer : public rtc::VideoSourceInterface<VideoFrame> {
public: public:
TestVideoCapturer(); class FramePreprocessor {
public:
virtual ~FramePreprocessor() = default;
virtual VideoFrame Preprocess(const VideoFrame& frame) = 0;
};
~TestVideoCapturer() override; ~TestVideoCapturer() override;
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override; const rtc::VideoSinkWants& wants) override;
void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override; void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
void SetFramePreprocessor(std::unique_ptr<FramePreprocessor> preprocessor) {
rtc::CritScope crit(&lock_);
preprocessor_ = std::move(preprocessor);
}
protected: protected:
void OnFrame(const VideoFrame& frame); void OnFrame(const VideoFrame& frame);
@ -37,7 +48,10 @@ class TestVideoCapturer : public rtc::VideoSourceInterface<VideoFrame> {
private: private:
void UpdateVideoAdapter(); void UpdateVideoAdapter();
VideoFrame MaybePreprocess(const VideoFrame& frame);
rtc::CriticalSection lock_;
std::unique_ptr<FramePreprocessor> preprocessor_ RTC_GUARDED_BY(lock_);
rtc::VideoBroadcaster broadcaster_; rtc::VideoBroadcaster broadcaster_;
cricket::VideoAdapter video_adapter_; cricket::VideoAdapter video_adapter_;
}; };