|
| 1 | +/* |
| 2 | + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. |
| 3 | + * |
| 4 | + * Use of this source code is governed by a BSD-style license |
| 5 | + * that can be found in the LICENSE file in the root of the source |
| 6 | + * tree. An additional intellectual property rights grant can be found |
| 7 | + * in the file PATENTS. All contributing project authors may |
| 8 | + * be found in the AUTHORS file in the root of the source tree. |
| 9 | + */ |
| 10 | +#include "test/pc/e2e/media/media_helper.h" |
| 11 | + |
| 12 | +#include <utility> |
| 13 | + |
| 14 | +#include "api/test/create_frame_generator.h" |
| 15 | +#include "test/frame_generator_capturer.h" |
| 16 | +#include "test/platform_video_capturer.h" |
| 17 | +#include "test/testsupport/file_utils.h" |
| 18 | + |
| 19 | +namespace webrtc { |
| 20 | +namespace webrtc_pc_e2e { |
| 21 | +namespace { |
| 22 | + |
| 23 | +using VideoConfig = |
| 24 | + ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig; |
| 25 | +using AudioConfig = |
| 26 | + ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::AudioConfig; |
| 27 | +using VideoGeneratorType = ::webrtc::webrtc_pc_e2e:: |
| 28 | + PeerConnectionE2EQualityTestFixture::VideoGeneratorType; |
| 29 | + |
| 30 | +} // namespace |
| 31 | + |
| 32 | +MediaHelper::~MediaHelper() { |
| 33 | + for (const auto& video_writer : video_writers_) { |
| 34 | + video_writer->Close(); |
| 35 | + } |
| 36 | + video_writers_.clear(); |
| 37 | +} |
| 38 | + |
| 39 | +void MediaHelper::MaybeAddAudio(TestPeer* peer) { |
| 40 | + if (!peer->params()->audio_config) { |
| 41 | + return; |
| 42 | + } |
| 43 | + const AudioConfig& audio_config = peer->params()->audio_config.value(); |
| 44 | + rtc::scoped_refptr<webrtc::AudioSourceInterface> source = |
| 45 | + peer->pc_factory()->CreateAudioSource(audio_config.audio_options); |
| 46 | + rtc::scoped_refptr<AudioTrackInterface> track = |
| 47 | + peer->pc_factory()->CreateAudioTrack(*audio_config.stream_label, source); |
| 48 | + std::string sync_group = audio_config.sync_group |
| 49 | + ? audio_config.sync_group.value() |
| 50 | + : audio_config.stream_label.value(); |
| 51 | + peer->AddTrack(track, {sync_group, *audio_config.stream_label}); |
| 52 | +} |
| 53 | + |
| 54 | +std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>> |
| 55 | +MediaHelper::MaybeAddVideo(TestPeer* peer) { |
| 56 | + // Params here valid because of pre-run validation. |
| 57 | + Params* params = peer->params(); |
| 58 | + std::vector<rtc::scoped_refptr<TestVideoCapturerVideoTrackSource>> out; |
| 59 | + for (size_t i = 0; i < params->video_configs.size(); ++i) { |
| 60 | + auto video_config = params->video_configs[i]; |
| 61 | + // Setup input video source into peer connection. |
| 62 | + test::VideoFrameWriter* writer = |
| 63 | + MaybeCreateVideoWriter(video_config.input_dump_file_name, video_config); |
| 64 | + std::unique_ptr<test::TestVideoCapturer> capturer = CreateVideoCapturer( |
| 65 | + video_config, peer->ReleaseVideoGenerator(i), |
| 66 | + video_quality_analyzer_injection_helper_->CreateFramePreprocessor( |
| 67 | + video_config, writer)); |
| 68 | + rtc::scoped_refptr<TestVideoCapturerVideoTrackSource> source = |
| 69 | + new rtc::RefCountedObject<TestVideoCapturerVideoTrackSource>( |
| 70 | + std::move(capturer), |
| 71 | + /*is_screencast=*/video_config.screen_share_config && |
| 72 | + video_config.screen_share_config->use_text_content_hint); |
| 73 | + out.push_back(source); |
| 74 | + RTC_LOG(INFO) << "Adding video with video_config.stream_label=" |
| 75 | + << video_config.stream_label.value(); |
| 76 | + rtc::scoped_refptr<VideoTrackInterface> track = |
| 77 | + peer->pc_factory()->CreateVideoTrack(video_config.stream_label.value(), |
| 78 | + source); |
| 79 | + if (video_config.screen_share_config && |
| 80 | + video_config.screen_share_config->use_text_content_hint) { |
| 81 | + track->set_content_hint(VideoTrackInterface::ContentHint::kText); |
| 82 | + } |
| 83 | + std::string sync_group = video_config.sync_group |
| 84 | + ? video_config.sync_group.value() |
| 85 | + : video_config.stream_label.value(); |
| 86 | + RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> sender = |
| 87 | + peer->AddTrack(track, {sync_group, *video_config.stream_label}); |
| 88 | + RTC_CHECK(sender.ok()); |
| 89 | + if (video_config.temporal_layers_count) { |
| 90 | + RtpParameters rtp_parameters = sender.value()->GetParameters(); |
| 91 | + for (auto& encoding_parameters : rtp_parameters.encodings) { |
| 92 | + encoding_parameters.num_temporal_layers = |
| 93 | + video_config.temporal_layers_count; |
| 94 | + } |
| 95 | + RTCError res = sender.value()->SetParameters(rtp_parameters); |
| 96 | + RTC_CHECK(res.ok()) << "Failed to set RTP parameters"; |
| 97 | + } |
| 98 | + } |
| 99 | + return out; |
| 100 | +} |
| 101 | + |
| 102 | +test::VideoFrameWriter* MediaHelper::MaybeCreateVideoWriter( |
| 103 | + absl::optional<std::string> file_name, |
| 104 | + const VideoConfig& config) { |
| 105 | + if (!file_name) { |
| 106 | + return nullptr; |
| 107 | + } |
| 108 | + // TODO(titovartem) create only one file writer for simulcast video track. |
| 109 | + // For now this code will be invoked for each simulcast stream separately, but |
| 110 | + // only one file will be used. |
| 111 | + auto video_writer = std::make_unique<test::Y4mVideoFrameWriterImpl>( |
| 112 | + file_name.value(), config.width, config.height, config.fps); |
| 113 | + test::VideoFrameWriter* out = video_writer.get(); |
| 114 | + video_writers_.push_back(std::move(video_writer)); |
| 115 | + return out; |
| 116 | +} |
| 117 | + |
| 118 | +std::unique_ptr<test::TestVideoCapturer> MediaHelper::CreateVideoCapturer( |
| 119 | + const VideoConfig& video_config, |
| 120 | + std::unique_ptr<test::FrameGeneratorInterface> generator, |
| 121 | + std::unique_ptr<test::TestVideoCapturer::FramePreprocessor> |
| 122 | + frame_preprocessor) { |
| 123 | + if (video_config.capturing_device_index) { |
| 124 | + std::unique_ptr<test::TestVideoCapturer> capturer = |
| 125 | + test::CreateVideoCapturer(video_config.width, video_config.height, |
| 126 | + video_config.fps, |
| 127 | + *video_config.capturing_device_index); |
| 128 | + RTC_CHECK(capturer) |
| 129 | + << "Failed to obtain input stream from capturing device #" |
| 130 | + << *video_config.capturing_device_index; |
| 131 | + capturer->SetFramePreprocessor(std::move(frame_preprocessor)); |
| 132 | + return capturer; |
| 133 | + } |
| 134 | + |
| 135 | + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = nullptr; |
| 136 | + if (generator) { |
| 137 | + frame_generator = std::move(generator); |
| 138 | + } |
| 139 | + |
| 140 | + if (video_config.generator) { |
| 141 | + absl::optional<test::FrameGeneratorInterface::OutputType> |
| 142 | + frame_generator_type = absl::nullopt; |
| 143 | + if (video_config.generator == VideoGeneratorType::kDefault) { |
| 144 | + frame_generator_type = test::FrameGeneratorInterface::OutputType::kI420; |
| 145 | + } else if (video_config.generator == VideoGeneratorType::kI420A) { |
| 146 | + frame_generator_type = test::FrameGeneratorInterface::OutputType::kI420A; |
| 147 | + } else if (video_config.generator == VideoGeneratorType::kI010) { |
| 148 | + frame_generator_type = test::FrameGeneratorInterface::OutputType::kI010; |
| 149 | + } |
| 150 | + frame_generator = |
| 151 | + test::CreateSquareFrameGenerator(static_cast<int>(video_config.width), |
| 152 | + static_cast<int>(video_config.height), |
| 153 | + frame_generator_type, absl::nullopt); |
| 154 | + } |
| 155 | + if (video_config.input_file_name) { |
| 156 | + frame_generator = test::CreateFromYuvFileFrameGenerator( |
| 157 | + std::vector<std::string>(/*count=*/1, |
| 158 | + video_config.input_file_name.value()), |
| 159 | + video_config.width, video_config.height, /*frame_repeat_count=*/1); |
| 160 | + } |
| 161 | + if (video_config.screen_share_config) { |
| 162 | + frame_generator = CreateScreenShareFrameGenerator(video_config); |
| 163 | + } |
| 164 | + RTC_CHECK(frame_generator) << "Unsupported video_config input source"; |
| 165 | + |
| 166 | + auto capturer = std::make_unique<test::FrameGeneratorCapturer>( |
| 167 | + clock_, std::move(frame_generator), video_config.fps, |
| 168 | + *task_queue_factory_); |
| 169 | + capturer->SetFramePreprocessor(std::move(frame_preprocessor)); |
| 170 | + capturer->Init(); |
| 171 | + return capturer; |
| 172 | +} |
| 173 | + |
| 174 | +std::unique_ptr<test::FrameGeneratorInterface> |
| 175 | +MediaHelper::CreateScreenShareFrameGenerator(const VideoConfig& video_config) { |
| 176 | + RTC_CHECK(video_config.screen_share_config); |
| 177 | + if (video_config.screen_share_config->generate_slides) { |
| 178 | + return test::CreateSlideFrameGenerator( |
| 179 | + video_config.width, video_config.height, |
| 180 | + video_config.screen_share_config->slide_change_interval.seconds() * |
| 181 | + video_config.fps); |
| 182 | + } |
| 183 | + std::vector<std::string> slides = |
| 184 | + video_config.screen_share_config->slides_yuv_file_names; |
| 185 | + if (slides.empty()) { |
| 186 | + // If slides is empty we need to add default slides as source. In such case |
| 187 | + // video width and height is validated to be equal to kDefaultSlidesWidth |
| 188 | + // and kDefaultSlidesHeight. |
| 189 | + slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv")); |
| 190 | + slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv")); |
| 191 | + slides.push_back(test::ResourcePath("photo_1850_1110", "yuv")); |
| 192 | + slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv")); |
| 193 | + } |
| 194 | + if (!video_config.screen_share_config->scrolling_params) { |
| 195 | + // Cycle image every slide_change_interval seconds. |
| 196 | + return test::CreateFromYuvFileFrameGenerator( |
| 197 | + slides, video_config.width, video_config.height, |
| 198 | + video_config.screen_share_config->slide_change_interval.seconds() * |
| 199 | + video_config.fps); |
| 200 | + } |
| 201 | + |
| 202 | + // |pause_duration| is nonnegative. It is validated in ValidateParams(...). |
| 203 | + TimeDelta pause_duration = |
| 204 | + video_config.screen_share_config->slide_change_interval - |
| 205 | + video_config.screen_share_config->scrolling_params->duration; |
| 206 | + |
| 207 | + return test::CreateScrollingInputFromYuvFilesFrameGenerator( |
| 208 | + clock_, slides, |
| 209 | + video_config.screen_share_config->scrolling_params->source_width, |
| 210 | + video_config.screen_share_config->scrolling_params->source_height, |
| 211 | + video_config.width, video_config.height, |
| 212 | + video_config.screen_share_config->scrolling_params->duration.ms(), |
| 213 | + pause_duration.ms()); |
| 214 | +} |
| 215 | + |
| 216 | +} // namespace webrtc_pc_e2e |
| 217 | +} // namespace webrtc |
0 commit comments