xref: /aosp_15_r20/external/webrtc/rtc_tools/rtp_generator/rtp_generator.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2019 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 
11 #include "rtc_tools/rtp_generator/rtp_generator.h"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <utility>
16 
17 #include "api/task_queue/default_task_queue_factory.h"
18 #include "api/test/create_frame_generator.h"
19 #include "api/video_codecs/builtin_video_decoder_factory.h"
20 #include "api/video_codecs/builtin_video_encoder_factory.h"
21 #include "api/video_codecs/video_encoder.h"
22 #include "media/base/media_constants.h"
23 #include "rtc_base/strings/json.h"
24 #include "rtc_base/system/file_wrapper.h"
25 #include "rtc_base/thread.h"
26 #include "test/testsupport/file_utils.h"
27 #include "video/config/encoder_stream_factory.h"
28 #include "video/config/video_encoder_config.h"
29 
30 namespace webrtc {
31 namespace {
32 
33 // Payload types.
34 constexpr int kPayloadTypeVp8 = 125;
35 constexpr int kPayloadTypeVp9 = 124;
36 constexpr int kPayloadTypeH264 = 123;
37 constexpr int kFakeVideoSendPayloadType = 122;
38 
39 // Defaults
40 constexpr int kDefaultSsrc = 1337;
41 constexpr int kMaxConfigBufferSize = 8192;
42 
43 // Utility function to validate a correct codec type has been passed in.
IsValidCodecType(const std::string & codec_name)44 bool IsValidCodecType(const std::string& codec_name) {
45   return cricket::kVp8CodecName == codec_name ||
46          cricket::kVp9CodecName == codec_name ||
47          cricket::kH264CodecName == codec_name;
48 }
49 
50 // Utility function to return some base payload type for a codec_name.
GetDefaultTypeForPayloadName(const std::string & codec_name)51 int GetDefaultTypeForPayloadName(const std::string& codec_name) {
52   if (cricket::kVp8CodecName == codec_name) {
53     return kPayloadTypeVp8;
54   }
55   if (cricket::kVp9CodecName == codec_name) {
56     return kPayloadTypeVp9;
57   }
58   if (cricket::kH264CodecName == codec_name) {
59     return kPayloadTypeH264;
60   }
61   return kFakeVideoSendPayloadType;
62 }
63 
64 // Creates a single VideoSendStream configuration.
65 absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
ParseVideoSendStreamConfig(const Json::Value & json)66 ParseVideoSendStreamConfig(const Json::Value& json) {
67   RtpGeneratorOptions::VideoSendStreamConfig config;
68 
69   // Parse video source settings.
70   if (!rtc::GetIntFromJsonObject(json, "duration_ms", &config.duration_ms)) {
71     RTC_LOG(LS_WARNING) << "duration_ms not specified using default: "
72                         << config.duration_ms;
73   }
74   if (!rtc::GetIntFromJsonObject(json, "video_width", &config.video_width)) {
75     RTC_LOG(LS_WARNING) << "video_width not specified using default: "
76                         << config.video_width;
77   }
78   if (!rtc::GetIntFromJsonObject(json, "video_height", &config.video_height)) {
79     RTC_LOG(LS_WARNING) << "video_height not specified using default: "
80                         << config.video_height;
81   }
82   if (!rtc::GetIntFromJsonObject(json, "video_fps", &config.video_fps)) {
83     RTC_LOG(LS_WARNING) << "video_fps not specified using default: "
84                         << config.video_fps;
85   }
86   if (!rtc::GetIntFromJsonObject(json, "num_squares", &config.num_squares)) {
87     RTC_LOG(LS_WARNING) << "num_squares not specified using default: "
88                         << config.num_squares;
89   }
90 
91   // Parse RTP settings for this configuration.
92   config.rtp.ssrcs.push_back(kDefaultSsrc);
93   Json::Value rtp_json;
94   if (!rtc::GetValueFromJsonObject(json, "rtp", &rtp_json)) {
95     RTC_LOG(LS_ERROR) << "video_streams must have an rtp section";
96     return absl::nullopt;
97   }
98   if (!rtc::GetStringFromJsonObject(rtp_json, "payload_name",
99                                     &config.rtp.payload_name)) {
100     RTC_LOG(LS_ERROR) << "rtp.payload_name must be specified";
101     return absl::nullopt;
102   }
103   if (!IsValidCodecType(config.rtp.payload_name)) {
104     RTC_LOG(LS_ERROR) << "rtp.payload_name must be VP8,VP9 or H264";
105     return absl::nullopt;
106   }
107 
108   config.rtp.payload_type =
109       GetDefaultTypeForPayloadName(config.rtp.payload_name);
110   if (!rtc::GetIntFromJsonObject(rtp_json, "payload_type",
111                                  &config.rtp.payload_type)) {
112     RTC_LOG(LS_WARNING)
113         << "rtp.payload_type not specified using default for codec type"
114         << config.rtp.payload_type;
115   }
116 
117   return config;
118 }
119 
120 }  // namespace
121 
ParseRtpGeneratorOptionsFromFile(const std::string & options_file)122 absl::optional<RtpGeneratorOptions> ParseRtpGeneratorOptionsFromFile(
123     const std::string& options_file) {
124   if (!test::FileExists(options_file)) {
125     RTC_LOG(LS_ERROR) << " configuration file does not exist";
126     return absl::nullopt;
127   }
128 
129   // Read the configuration file from disk.
130   FileWrapper config_file = FileWrapper::OpenReadOnly(options_file);
131   std::vector<char> raw_json_buffer(kMaxConfigBufferSize, 0);
132   size_t bytes_read =
133       config_file.Read(raw_json_buffer.data(), raw_json_buffer.size() - 1);
134   if (bytes_read == 0) {
135     RTC_LOG(LS_ERROR) << "Unable to read the configuration file.";
136     return absl::nullopt;
137   }
138 
139   // Parse the file as JSON
140   Json::CharReaderBuilder builder;
141   Json::Value json;
142   std::string error_message;
143   std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
144   if (!json_reader->parse(raw_json_buffer.data(),
145                           raw_json_buffer.data() + raw_json_buffer.size(),
146                           &json, &error_message)) {
147     RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file. Error:"
148                       << error_message;
149     return absl::nullopt;
150   }
151 
152   RtpGeneratorOptions gen_options;
153   for (const auto& video_stream_json : json["video_streams"]) {
154     absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
155         video_stream_config = ParseVideoSendStreamConfig(video_stream_json);
156     if (!video_stream_config.has_value()) {
157       RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file";
158       return absl::nullopt;
159     }
160     gen_options.video_streams.push_back(*video_stream_config);
161   }
162   return gen_options;
163 }
164 
RtpGenerator(const RtpGeneratorOptions & options)165 RtpGenerator::RtpGenerator(const RtpGeneratorOptions& options)
166     : options_(options),
167       video_encoder_factory_(CreateBuiltinVideoEncoderFactory()),
168       video_decoder_factory_(CreateBuiltinVideoDecoderFactory()),
169       video_bitrate_allocator_factory_(
170           CreateBuiltinVideoBitrateAllocatorFactory()),
171       event_log_(std::make_unique<RtcEventLogNull>()),
172       call_(Call::Create(CallConfig(event_log_.get()))),
173       task_queue_(CreateDefaultTaskQueueFactory()) {
174   constexpr int kMinBitrateBps = 30000;    // 30 Kbps
175   constexpr int kMaxBitrateBps = 2500000;  // 2.5 Mbps
176 
177   int stream_count = 0;
178   webrtc::VideoEncoder::EncoderInfo encoder_info;
179   for (const auto& send_config : options.video_streams) {
180     webrtc::VideoSendStream::Config video_config(this);
181     video_config.encoder_settings.encoder_factory =
182         video_encoder_factory_.get();
183     video_config.encoder_settings.bitrate_allocator_factory =
184         video_bitrate_allocator_factory_.get();
185     video_config.rtp = send_config.rtp;
186     // Update some required to be unique values.
187     stream_count++;
188     video_config.rtp.mid = "mid-" + std::to_string(stream_count);
189 
190     // Configure the video encoder configuration.
191     VideoEncoderConfig encoder_config;
192     encoder_config.content_type =
193         VideoEncoderConfig::ContentType::kRealtimeVideo;
194     encoder_config.codec_type =
195         PayloadStringToCodecType(video_config.rtp.payload_name);
196     if (video_config.rtp.payload_name == cricket::kVp8CodecName) {
197       VideoCodecVP8 settings = VideoEncoder::GetDefaultVp8Settings();
198       encoder_config.encoder_specific_settings =
199           rtc::make_ref_counted<VideoEncoderConfig::Vp8EncoderSpecificSettings>(
200               settings);
201     } else if (video_config.rtp.payload_name == cricket::kVp9CodecName) {
202       VideoCodecVP9 settings = VideoEncoder::GetDefaultVp9Settings();
203       encoder_config.encoder_specific_settings =
204           rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>(
205               settings);
206     } else if (video_config.rtp.payload_name == cricket::kH264CodecName) {
207       encoder_config.encoder_specific_settings = nullptr;
208     }
209     encoder_config.video_format.name = video_config.rtp.payload_name;
210     encoder_config.min_transmit_bitrate_bps = 0;
211     encoder_config.max_bitrate_bps = kMaxBitrateBps;
212     encoder_config.content_type =
213         VideoEncoderConfig::ContentType::kRealtimeVideo;
214 
215     // Configure the simulcast layers.
216     encoder_config.number_of_streams = video_config.rtp.ssrcs.size();
217     encoder_config.bitrate_priority = 1.0;
218     encoder_config.simulcast_layers.resize(encoder_config.number_of_streams);
219     for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
220       encoder_config.simulcast_layers[i].active = true;
221       encoder_config.simulcast_layers[i].min_bitrate_bps = kMinBitrateBps;
222       encoder_config.simulcast_layers[i].max_bitrate_bps = kMaxBitrateBps;
223       encoder_config.simulcast_layers[i].max_framerate = send_config.video_fps;
224     }
225 
226     encoder_config.video_stream_factory =
227         rtc::make_ref_counted<cricket::EncoderStreamFactory>(
228             video_config.rtp.payload_name, /*max qp*/ 56, /*screencast*/ false,
229             /*screenshare enabled*/ false, encoder_info);
230 
231     // Setup the fake video stream for this.
232     std::unique_ptr<test::FrameGeneratorCapturer> frame_generator =
233         std::make_unique<test::FrameGeneratorCapturer>(
234             Clock::GetRealTimeClock(),
235             test::CreateSquareFrameGenerator(send_config.video_width,
236                                              send_config.video_height,
237                                              absl::nullopt, absl::nullopt),
238             send_config.video_fps, *task_queue_);
239     frame_generator->Init();
240 
241     VideoSendStream* video_send_stream = call_->CreateVideoSendStream(
242         std::move(video_config), std::move(encoder_config));
243     video_send_stream->SetSource(
244         frame_generator.get(),
245         webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
246     // Store these objects so we can destropy them at the end.
247     frame_generators_.push_back(std::move(frame_generator));
248     video_send_streams_.push_back(video_send_stream);
249   }
250 }
251 
~RtpGenerator()252 RtpGenerator::~RtpGenerator() {
253   for (VideoSendStream* send_stream : video_send_streams_) {
254     call_->DestroyVideoSendStream(send_stream);
255   }
256 }
257 
GenerateRtpDump(const std::string & rtp_dump_path)258 void RtpGenerator::GenerateRtpDump(const std::string& rtp_dump_path) {
259   rtp_dump_writer_.reset(test::RtpFileWriter::Create(
260       test::RtpFileWriter::kRtpDump, rtp_dump_path));
261 
262   call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
263                                    webrtc::kNetworkUp);
264   for (VideoSendStream* send_stream : video_send_streams_) {
265     send_stream->Start();
266   }
267 
268   // Spinlock until all the durations end.
269   WaitUntilAllVideoStreamsFinish();
270 
271   call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
272                                    webrtc::kNetworkDown);
273 }
274 
SendRtp(const uint8_t * packet,size_t length,const webrtc::PacketOptions & options)275 bool RtpGenerator::SendRtp(const uint8_t* packet,
276                            size_t length,
277                            const webrtc::PacketOptions& options) {
278   test::RtpPacket rtp_packet = DataToRtpPacket(packet, length);
279   rtp_dump_writer_->WritePacket(&rtp_packet);
280   return true;
281 }
282 
SendRtcp(const uint8_t * packet,size_t length)283 bool RtpGenerator::SendRtcp(const uint8_t* packet, size_t length) {
284   test::RtpPacket rtcp_packet = DataToRtpPacket(packet, length);
285   rtp_dump_writer_->WritePacket(&rtcp_packet);
286   return true;
287 }
288 
GetMaxDuration() const289 int RtpGenerator::GetMaxDuration() const {
290   int max_end_ms = 0;
291   for (const auto& video_stream : options_.video_streams) {
292     max_end_ms = std::max(video_stream.duration_ms, max_end_ms);
293   }
294   return max_end_ms;
295 }
296 
WaitUntilAllVideoStreamsFinish()297 void RtpGenerator::WaitUntilAllVideoStreamsFinish() {
298   // Find the maximum duration required by the streams.
299   start_ms_ = Clock::GetRealTimeClock()->TimeInMilliseconds();
300   int64_t max_end_ms = start_ms_ + GetMaxDuration();
301 
302   int64_t current_time = 0;
303   do {
304     int64_t min_wait_time = 0;
305     current_time = Clock::GetRealTimeClock()->TimeInMilliseconds();
306     // Stop any streams that are no longer active.
307     for (size_t i = 0; i < options_.video_streams.size(); ++i) {
308       const int64_t end_ms = start_ms_ + options_.video_streams[i].duration_ms;
309       if (current_time > end_ms) {
310         video_send_streams_[i]->Stop();
311       } else {
312         min_wait_time = std::min(min_wait_time, end_ms - current_time);
313       }
314     }
315     rtc::Thread::Current()->SleepMs(min_wait_time);
316   } while (current_time < max_end_ms);
317 }
318 
DataToRtpPacket(const uint8_t * packet,size_t packet_len)319 test::RtpPacket RtpGenerator::DataToRtpPacket(const uint8_t* packet,
320                                               size_t packet_len) {
321   webrtc::test::RtpPacket rtp_packet;
322   memcpy(rtp_packet.data, packet, packet_len);
323   rtp_packet.length = packet_len;
324   rtp_packet.original_length = packet_len;
325   rtp_packet.time_ms =
326       webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_;
327   return rtp_packet;
328 }
329 
330 }  // namespace webrtc
331