blob: 6562f423f07b5d6b052ad67f2ba9ed3712df8648 [file] [log] [blame]
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +00001/*
2 * Copyright (c) 2014 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 <stdio.h>
12
Benjamin Wright90ab76d2018-08-23 11:33:29 -070013#include <fstream>
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000014#include <map>
kwiberg27f982b2016-03-01 11:52:33 -080015#include <memory>
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000016
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020017#include "absl/flags/flag.h"
18#include "absl/flags/parse.h"
Danil Chapovalov83bbe912019-08-07 12:24:53 +020019#include "api/rtc_event_log/rtc_event_log.h"
Sergey Silkin626f7ff2019-09-12 10:51:19 +020020#include "api/task_queue/default_task_queue_factory.h"
Danil Chapovalov99b71df2018-10-26 15:57:48 +020021#include "api/test/video/function_video_decoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "api/video_codecs/video_decoder.h"
23#include "call/call.h"
24#include "common_video/libyuv/include/webrtc_libyuv.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "media/engine/internal_decoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/string_to_number.h"
Sam Zackrissonb45bdb52018-10-02 16:25:59 +020028#include "rtc_base/strings/json.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "system_wrappers/include/clock.h"
31#include "system_wrappers/include/sleep.h"
Benjamin Wright8efafdf2019-01-11 10:48:42 -080032#include "test/call_config_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "test/call_test.h"
34#include "test/encoder_settings.h"
35#include "test/fake_decoder.h"
36#include "test/gtest.h"
37#include "test/null_transport.h"
38#include "test/rtp_file_reader.h"
Sergey Silkin626f7ff2019-09-12 10:51:19 +020039#include "test/rtp_header_parser.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "test/run_loop.h"
41#include "test/run_test.h"
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020042#include "test/test_video_capturer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "test/testsupport/frame_writer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044#include "test/video_renderer.h"
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000045
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020046// Flag for payload type.
47ABSL_FLAG(int,
48 media_payload_type,
49 webrtc::test::CallTest::kPayloadTypeVP8,
50 "Media payload type");
51
52// Flag for RED payload type.
53ABSL_FLAG(int,
54 red_payload_type,
55 webrtc::test::CallTest::kRedPayloadType,
56 "RED payload type");
57
58// Flag for ULPFEC payload type.
59ABSL_FLAG(int,
60 ulpfec_payload_type,
61 webrtc::test::CallTest::kUlpfecPayloadType,
62 "ULPFEC payload type");
63
64ABSL_FLAG(int,
65 media_payload_type_rtx,
66 webrtc::test::CallTest::kSendRtxPayloadType,
67 "Media over RTX payload type");
68
69ABSL_FLAG(int,
70 red_payload_type_rtx,
71 webrtc::test::CallTest::kRtxRedPayloadType,
72 "RED over RTX payload type");
73
74// Flag for SSRC.
75const std::string& DefaultSsrc() {
76 static const std::string ssrc =
77 std::to_string(webrtc::test::CallTest::kVideoSendSsrcs[0]);
78 return ssrc;
79}
80ABSL_FLAG(std::string, ssrc, DefaultSsrc().c_str(), "Incoming SSRC");
81
82const std::string& DefaultSsrcRtx() {
83 static const std::string ssrc_rtx =
84 std::to_string(webrtc::test::CallTest::kSendRtxSsrcs[0]);
85 return ssrc_rtx;
86}
87ABSL_FLAG(std::string, ssrc_rtx, DefaultSsrcRtx().c_str(), "Incoming RTX SSRC");
88
89// Flag for abs-send-time id.
90ABSL_FLAG(int, abs_send_time_id, -1, "RTP extension ID for abs-send-time");
91
92// Flag for transmission-offset id.
93ABSL_FLAG(int,
94 transmission_offset_id,
95 -1,
96 "RTP extension ID for transmission-offset");
97
98// Flag for rtpdump input file.
99ABSL_FLAG(std::string, input_file, "", "input file");
100
101ABSL_FLAG(std::string, config_file, "", "config file");
102
103// Flag for raw output files.
104ABSL_FLAG(std::string,
105 out_base,
106 "",
107 "Basename (excluding .jpg) for raw output");
108
109ABSL_FLAG(std::string,
110 decoder_bitstream_filename,
111 "",
112 "Decoder bitstream output file");
113
114// Flag for video codec.
115ABSL_FLAG(std::string, codec, "VP8", "Video codec");
116
oprypin6e09d872017-08-31 03:21:39 -0700117namespace {
118
119static bool ValidatePayloadType(int32_t payload_type) {
120 return payload_type > 0 && payload_type <= 127;
121}
122
123static bool ValidateSsrc(const char* ssrc_string) {
124 return rtc::StringToNumber<uint32_t>(ssrc_string).has_value();
125}
126
127static bool ValidateOptionalPayloadType(int32_t payload_type) {
128 return payload_type == -1 || ValidatePayloadType(payload_type);
129}
130
131static bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
132 return extension_id >= -1 && extension_id < 15;
133}
134
135bool ValidateInputFilenameNotEmpty(const std::string& string) {
136 return !string.empty();
137}
138
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200139static int MediaPayloadType() {
140 return absl::GetFlag(FLAGS_media_payload_type);
141}
142
143static int RedPayloadType() {
144 return absl::GetFlag(FLAGS_red_payload_type);
145}
146
147static int UlpfecPayloadType() {
148 return absl::GetFlag(FLAGS_ulpfec_payload_type);
149}
150
151static int MediaPayloadTypeRtx() {
152 return absl::GetFlag(FLAGS_media_payload_type_rtx);
153}
154
155static int RedPayloadTypeRtx() {
156 return absl::GetFlag(FLAGS_red_payload_type_rtx);
157}
158
159static uint32_t Ssrc() {
160 return rtc::StringToNumber<uint32_t>(absl::GetFlag(FLAGS_ssrc)).value();
161}
162
163static uint32_t SsrcRtx() {
164 return rtc::StringToNumber<uint32_t>(absl::GetFlag(FLAGS_ssrc_rtx)).value();
165}
166
167static int AbsSendTimeId() {
168 return absl::GetFlag(FLAGS_abs_send_time_id);
169}
170
171static int TransmissionOffsetId() {
172 return absl::GetFlag(FLAGS_transmission_offset_id);
173}
174
175static std::string InputFile() {
176 return absl::GetFlag(FLAGS_input_file);
177}
178
179static std::string ConfigFile() {
180 return absl::GetFlag(FLAGS_config_file);
181}
182
183static std::string OutBase() {
184 return absl::GetFlag(FLAGS_out_base);
185}
186
187static std::string DecoderBitstreamFilename() {
188 return absl::GetFlag(FLAGS_decoder_bitstream_filename);
189}
190
191static std::string Codec() {
192 return absl::GetFlag(FLAGS_codec);
193}
194
oprypin6e09d872017-08-31 03:21:39 -0700195} // namespace
196
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000197namespace webrtc {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000198
199static const uint32_t kReceiverLocalSsrc = 0x123456;
200
nisse7ade7b32016-03-23 04:48:10 -0700201class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000202 public:
nisse7ade7b32016-03-23 04:48:10 -0700203 FileRenderPassthrough(const std::string& basename,
204 rtc::VideoSinkInterface<VideoFrame>* renderer)
philipel99b63452017-08-25 07:24:21 -0700205 : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000206
Mirko Bonadeife055c12019-01-29 22:53:28 +0100207 ~FileRenderPassthrough() override {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200208 if (file_)
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000209 fclose(file_);
210 }
211
212 private:
nisseeb83a1a2016-03-21 01:27:56 -0700213 void OnFrame(const VideoFrame& video_frame) override {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200214 if (renderer_)
nisseeb83a1a2016-03-21 01:27:56 -0700215 renderer_->OnFrame(video_frame);
philipel99b63452017-08-25 07:24:21 -0700216
pbosbb36fdf2015-07-09 07:48:14 -0700217 if (basename_.empty())
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000218 return;
philipel99b63452017-08-25 07:24:21 -0700219
220 std::stringstream filename;
221 filename << basename_ << count_++ << "_" << video_frame.timestamp()
222 << ".jpg";
223
philipel99b63452017-08-25 07:24:21 -0700224 test::JpegFrameWriter frame_writer(filename.str());
225 RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000226 }
227
228 const std::string basename_;
nisse7ade7b32016-03-23 04:48:10 -0700229 rtc::VideoSinkInterface<VideoFrame>* const renderer_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000230 FILE* file_;
231 size_t count_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000232};
233
Niels Möllerf88a22c2018-06-19 17:05:03 +0200234class DecoderBitstreamFileWriter : public test::FakeDecoder {
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000235 public:
236 explicit DecoderBitstreamFileWriter(const char* filename)
237 : file_(fopen(filename, "wb")) {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200238 RTC_DCHECK(file_);
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000239 }
Mirko Bonadeife055c12019-01-29 22:53:28 +0100240 ~DecoderBitstreamFileWriter() override { fclose(file_); }
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000241
Niels Möllerf88a22c2018-06-19 17:05:03 +0200242 int32_t Decode(const EncodedImage& encoded_frame,
Benjamin Wright8efafdf2019-01-11 10:48:42 -0800243 bool /* missing_frames */,
Benjamin Wright8efafdf2019-01-11 10:48:42 -0800244 int64_t /* render_time_ms */) override {
Niels Möller77536a22019-01-15 08:50:01 +0100245 if (fwrite(encoded_frame.data(), 1, encoded_frame.size(), file_) <
246 encoded_frame.size()) {
Niels Möllerf88a22c2018-06-19 17:05:03 +0200247 RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
248 return WEBRTC_VIDEO_CODEC_ERROR;
249 }
250 return WEBRTC_VIDEO_CODEC_OK;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000251 }
252
253 private:
254 FILE* file_;
255};
256
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700257// The RtpReplayer is responsible for parsing the configuration provided by the
258// user, setting up the windows, recieve streams and decoders and then replaying
259// the provided RTP dump.
260class RtpReplayer final {
261 public:
262 // Replay a rtp dump with an optional json configuration.
263 static void Replay(const std::string& replay_config_path,
264 const std::string& rtp_dump_path) {
Sergey Silkin626f7ff2019-09-12 10:51:19 +0200265 std::unique_ptr<webrtc::TaskQueueFactory> task_queue_factory =
266 webrtc::CreateDefaultTaskQueueFactory();
Danil Chapovalov83bbe912019-08-07 12:24:53 +0200267 webrtc::RtcEventLogNull event_log;
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700268 Call::Config call_config(&event_log);
Sergey Silkin626f7ff2019-09-12 10:51:19 +0200269 call_config.task_queue_factory = task_queue_factory.get();
Mirko Bonadei05cf6be2019-01-31 21:38:12 +0100270 std::unique_ptr<Call> call(Call::Create(call_config));
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700271 std::unique_ptr<StreamState> stream_state;
272 // Attempt to load the configuration
273 if (replay_config_path.empty()) {
274 stream_state = ConfigureFromFlags(rtp_dump_path, call.get());
275 } else {
276 stream_state = ConfigureFromFile(replay_config_path, call.get());
277 }
278 if (stream_state == nullptr) {
279 return;
280 }
281 // Attempt to create an RtpReader from the input file.
282 std::unique_ptr<test::RtpFileReader> rtp_reader =
283 CreateRtpReader(rtp_dump_path);
284 if (rtp_reader == nullptr) {
285 return;
286 }
287 // Start replaying the provided stream now that it has been configured.
288 for (const auto& receive_stream : stream_state->receive_streams) {
289 receive_stream->Start();
290 }
291 ReplayPackets(call.get(), rtp_reader.get());
292 for (const auto& receive_stream : stream_state->receive_streams) {
293 call->DestroyVideoReceiveStream(receive_stream);
294 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000295 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000296
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700297 private:
298 // Holds all the shared memory structures required for a recieve stream. This
299 // structure is used to prevent members being deallocated before the replay
300 // has been finished.
301 struct StreamState {
302 test::NullTransport transport;
303 std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
304 std::vector<VideoReceiveStream*> receive_streams;
Niels Möllercbcbc222018-09-28 09:07:24 +0200305 std::unique_ptr<VideoDecoderFactory> decoder_factory;
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700306 };
307
308 // Loads multiple configurations from the provided configuration file.
309 static std::unique_ptr<StreamState> ConfigureFromFile(
310 const std::string& config_path,
311 Call* call) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200312 auto stream_state = std::make_unique<StreamState>();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700313 // Parse the configuration file.
314 std::ifstream config_file(config_path);
315 std::stringstream raw_json_buffer;
316 raw_json_buffer << config_file.rdbuf();
317 std::string raw_json = raw_json_buffer.str();
318 Json::Reader json_reader;
319 Json::Value json_configs;
320 if (!json_reader.parse(raw_json, json_configs)) {
321 fprintf(stderr, "Error parsing JSON config\n");
322 fprintf(stderr, "%s\n", json_reader.getFormatedErrorMessages().c_str());
323 return nullptr;
324 }
325
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200326 stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700327 size_t config_count = 0;
328 for (const auto& json : json_configs) {
329 // Create the configuration and parse the JSON into the config.
Benjamin Wright8efafdf2019-01-11 10:48:42 -0800330 auto receive_config =
331 ParseVideoReceiveStreamJsonConfig(&(stream_state->transport), json);
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700332 // Instantiate the underlying decoder.
333 for (auto& decoder : receive_config.decoders) {
Niels Möllercbcbc222018-09-28 09:07:24 +0200334 decoder = test::CreateMatchingDecoder(decoder.payload_type,
335 decoder.video_format.name);
336 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700337 }
338 // Create a window for this config.
339 std::stringstream window_title;
340 window_title << "Playback Video (" << config_count++ << ")";
341 stream_state->sinks.emplace_back(
342 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
343 // Create a receive stream for this config.
344 receive_config.renderer = stream_state->sinks.back().get();
345 stream_state->receive_streams.emplace_back(
346 call->CreateVideoReceiveStream(std::move(receive_config)));
347 }
348 return stream_state;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000349 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000350
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700351 // Loads the base configuration from flags passed in on the commandline.
352 static std::unique_ptr<StreamState> ConfigureFromFlags(
353 const std::string& rtp_dump_path,
354 Call* call) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200355 auto stream_state = std::make_unique<StreamState>();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700356 // Create the video renderers. We must add both to the stream state to keep
357 // them from deallocating.
358 std::stringstream window_title;
359 window_title << "Playback Video (" << rtp_dump_path << ")";
360 std::unique_ptr<test::VideoRenderer> playback_video(
361 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200362 auto file_passthrough = std::make_unique<FileRenderPassthrough>(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200363 OutBase(), playback_video.get());
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700364 stream_state->sinks.push_back(std::move(playback_video));
365 stream_state->sinks.push_back(std::move(file_passthrough));
366 // Setup the configuration from the flags.
367 VideoReceiveStream::Config receive_config(&(stream_state->transport));
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200368 receive_config.rtp.remote_ssrc = Ssrc();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700369 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200370 receive_config.rtp.rtx_ssrc = SsrcRtx();
371 receive_config.rtp.rtx_associated_payload_types[MediaPayloadTypeRtx()] =
372 MediaPayloadType();
373 receive_config.rtp.rtx_associated_payload_types[RedPayloadTypeRtx()] =
374 RedPayloadType();
375 receive_config.rtp.ulpfec_payload_type = UlpfecPayloadType();
376 receive_config.rtp.red_payload_type = RedPayloadType();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700377 receive_config.rtp.nack.rtp_history_ms = 1000;
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200378 if (TransmissionOffsetId() != -1) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700379 receive_config.rtp.extensions.push_back(RtpExtension(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200380 RtpExtension::kTimestampOffsetUri, TransmissionOffsetId()));
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700381 }
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200382 if (AbsSendTimeId() != -1) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700383 receive_config.rtp.extensions.push_back(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200384 RtpExtension(RtpExtension::kAbsSendTimeUri, AbsSendTimeId()));
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700385 }
386 receive_config.renderer = stream_state->sinks.back().get();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000387
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700388 // Setup the receiving stream
389 VideoReceiveStream::Decoder decoder;
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200390 decoder = test::CreateMatchingDecoder(MediaPayloadType(), Codec());
391 if (DecoderBitstreamFilename().empty()) {
Niels Möllercbcbc222018-09-28 09:07:24 +0200392 stream_state->decoder_factory =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200393 std::make_unique<InternalDecoderFactory>();
Niels Möllercbcbc222018-09-28 09:07:24 +0200394 } else {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700395 // Replace decoder with file writer if we're writing the bitstream to a
396 // file instead.
Niels Möllercbcbc222018-09-28 09:07:24 +0200397 stream_state->decoder_factory =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200398 std::make_unique<test::FunctionVideoDecoderFactory>([]() {
399 return std::make_unique<DecoderBitstreamFileWriter>(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200400 DecoderBitstreamFilename().c_str());
Niels Möllercbcbc222018-09-28 09:07:24 +0200401 });
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700402 }
Niels Möllercbcbc222018-09-28 09:07:24 +0200403 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700404 receive_config.decoders.push_back(decoder);
405
406 stream_state->receive_streams.emplace_back(
407 call->CreateVideoReceiveStream(std::move(receive_config)));
408 return stream_state;
409 }
410
411 static std::unique_ptr<test::RtpFileReader> CreateRtpReader(
412 const std::string& rtp_dump_path) {
413 std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
414 test::RtpFileReader::kRtpDump, rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200415 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700416 rtp_reader.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap,
417 rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200418 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700419 fprintf(
420 stderr,
421 "Couldn't open input file as either a rtpdump or .pcap. Note "
422 "that .pcapng is not supported.\nTrying to interpret the file as "
423 "length/packet interleaved.\n");
424 rtp_reader.reset(test::RtpFileReader::Create(
425 test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
426 if (!rtp_reader) {
427 fprintf(stderr,
428 "Unable to open input file with any supported format\n");
429 return nullptr;
430 }
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000431 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000432 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700433 return rtp_reader;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000434 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000435
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700436 static void ReplayPackets(Call* call, test::RtpFileReader* rtp_reader) {
437 int64_t replay_start_ms = -1;
438 int num_packets = 0;
439 std::map<uint32_t, int> unknown_packets;
440 while (true) {
441 int64_t now_ms = rtc::TimeMillis();
442 if (replay_start_ms == -1) {
443 replay_start_ms = now_ms;
444 }
philipel02f03962018-01-11 17:28:35 +0100445
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700446 test::RtpPacket packet;
447 if (!rtp_reader->NextPacket(&packet)) {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000448 break;
449 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700450
451 int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
452 if (deliver_in_ms > 0) {
453 SleepMs(deliver_in_ms);
454 }
455
456 ++num_packets;
457 switch (call->Receiver()->DeliverPacket(
458 webrtc::MediaType::VIDEO,
459 rtc::CopyOnWriteBuffer(packet.data, packet.length),
460 /* packet_time_us */ -1)) {
461 case PacketReceiver::DELIVERY_OK:
462 break;
463 case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
464 RTPHeader header;
Sergey Silkin626f7ff2019-09-12 10:51:19 +0200465 std::unique_ptr<RtpHeaderParser> parser(
466 RtpHeaderParser::CreateForTest());
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700467 parser->Parse(packet.data, packet.length, &header);
468 if (unknown_packets[header.ssrc] == 0)
469 fprintf(stderr, "Unknown SSRC: %u!\n", header.ssrc);
470 ++unknown_packets[header.ssrc];
471 break;
472 }
473 case PacketReceiver::DELIVERY_PACKET_ERROR: {
474 fprintf(stderr,
475 "Packet error, corrupt packets or incorrect setup?\n");
476 RTPHeader header;
Sergey Silkin626f7ff2019-09-12 10:51:19 +0200477 std::unique_ptr<RtpHeaderParser> parser(
478 RtpHeaderParser::CreateForTest());
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700479 parser->Parse(packet.data, packet.length, &header);
480 fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
481 packet.length, header.payloadType, header.sequenceNumber,
482 header.timestamp, header.ssrc);
483 break;
484 }
philipp.hancke7b589602017-01-26 04:54:04 -0800485 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000486 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700487 fprintf(stderr, "num_packets: %d\n", num_packets);
488
489 for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
490 it != unknown_packets.end(); ++it) {
491 fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
492 it->second);
493 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000494 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700495}; // class RtpReplayer
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000496
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700497void RtpReplay() {
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200498 RtpReplayer::Replay(ConfigFile(), InputFile());
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000499}
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700500
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000501} // namespace webrtc
502
503int main(int argc, char* argv[]) {
504 ::testing::InitGoogleTest(&argc, argv);
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200505 absl::ParseCommandLine(argc, argv);
oprypin6e09d872017-08-31 03:21:39 -0700506
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200507 RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type)));
508 RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type_rtx)));
509 RTC_CHECK(ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type)));
philipel752968e2017-12-05 12:40:28 +0100510 RTC_CHECK(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200511 ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type_rtx)));
philipel752968e2017-12-05 12:40:28 +0100512 RTC_CHECK(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200513 ValidateOptionalPayloadType(absl::GetFlag(FLAGS_ulpfec_payload_type)));
514 RTC_CHECK(ValidateSsrc(absl::GetFlag(FLAGS_ssrc).c_str()));
515 RTC_CHECK(ValidateSsrc(absl::GetFlag(FLAGS_ssrc_rtx).c_str()));
Yves Gerey665174f2018-06-19 15:03:05 +0200516 RTC_CHECK(
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200517 ValidateRtpHeaderExtensionId(absl::GetFlag(FLAGS_abs_send_time_id)));
518 RTC_CHECK(ValidateRtpHeaderExtensionId(
519 absl::GetFlag(FLAGS_transmission_offset_id)));
520 RTC_CHECK(ValidateInputFilenameNotEmpty(absl::GetFlag(FLAGS_input_file)));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000521
522 webrtc::test::RunTest(webrtc::RtpReplay);
523 return 0;
524}