blob: 6cfb8c1b71ca64e033da9aca8d25b2014b96309d [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
Steve Anton40d55332019-01-07 10:21:47 -080017#include "absl/memory/memory.h"
Danil Chapovalov99b71df2018-10-26 15:57:48 +020018#include "api/test/video/function_video_decoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/video_codecs/video_decoder.h"
20#include "call/call.h"
21#include "common_video/libyuv/include/webrtc_libyuv.h"
22#include "logging/rtc_event_log/rtc_event_log.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/engine/internal_decoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/rtp_rtcp/include/rtp_header_parser.h"
25#include "rtc_base/checks.h"
Benjamin Wright90ab76d2018-08-23 11:33:29 -070026#include "rtc_base/file.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/flags.h"
28#include "rtc_base/string_to_number.h"
Sam Zackrissonb45bdb52018-10-02 16:25:59 +020029#include "rtc_base/strings/json.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "system_wrappers/include/clock.h"
32#include "system_wrappers/include/sleep.h"
Benjamin Wright8efafdf2019-01-11 10:48:42 -080033#include "test/call_config_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "test/call_test.h"
35#include "test/encoder_settings.h"
36#include "test/fake_decoder.h"
37#include "test/gtest.h"
38#include "test/null_transport.h"
39#include "test/rtp_file_reader.h"
40#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
oprypin6e09d872017-08-31 03:21:39 -070046namespace {
47
48static bool ValidatePayloadType(int32_t payload_type) {
49 return payload_type > 0 && payload_type <= 127;
50}
51
52static bool ValidateSsrc(const char* ssrc_string) {
53 return rtc::StringToNumber<uint32_t>(ssrc_string).has_value();
54}
55
56static bool ValidateOptionalPayloadType(int32_t payload_type) {
57 return payload_type == -1 || ValidatePayloadType(payload_type);
58}
59
60static bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
61 return extension_id >= -1 && extension_id < 15;
62}
63
64bool ValidateInputFilenameNotEmpty(const std::string& string) {
65 return !string.empty();
66}
67
68} // namespace
69
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000070namespace webrtc {
71namespace flags {
72
73// TODO(pbos): Multiple receivers.
74
75// Flag for payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020076WEBRTC_DEFINE_int(media_payload_type,
77 test::CallTest::kPayloadTypeVP8,
78 "Media payload type");
philipel752968e2017-12-05 12:40:28 +010079static int MediaPayloadType() {
80 return static_cast<int>(FLAG_media_payload_type);
81}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000082
philipel752968e2017-12-05 12:40:28 +010083// Flag for RED payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020084WEBRTC_DEFINE_int(red_payload_type,
85 test::CallTest::kRedPayloadType,
86 "RED payload type");
philipel752968e2017-12-05 12:40:28 +010087static int RedPayloadType() {
88 return static_cast<int>(FLAG_red_payload_type);
89}
90
91// Flag for ULPFEC payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020092WEBRTC_DEFINE_int(ulpfec_payload_type,
93 test::CallTest::kUlpfecPayloadType,
94 "ULPFEC payload type");
philipel752968e2017-12-05 12:40:28 +010095static int UlpfecPayloadType() {
96 return static_cast<int>(FLAG_ulpfec_payload_type);
97}
98
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020099WEBRTC_DEFINE_int(media_payload_type_rtx,
100 test::CallTest::kSendRtxPayloadType,
101 "Media over RTX payload type");
philipel752968e2017-12-05 12:40:28 +0100102static int MediaPayloadTypeRtx() {
103 return static_cast<int>(FLAG_media_payload_type_rtx);
104}
105
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200106WEBRTC_DEFINE_int(red_payload_type_rtx,
107 test::CallTest::kRtxRedPayloadType,
108 "RED over RTX payload type");
philipel752968e2017-12-05 12:40:28 +0100109static int RedPayloadTypeRtx() {
110 return static_cast<int>(FLAG_red_payload_type_rtx);
ilnik863f03b2017-07-11 02:38:36 -0700111}
ilnik863f03b2017-07-11 02:38:36 -0700112
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000113// Flag for SSRC.
oprypin6e09d872017-08-31 03:21:39 -0700114const std::string& DefaultSsrc() {
Yves Gerey665174f2018-06-19 15:03:05 +0200115 static const std::string ssrc =
116 std::to_string(test::CallTest::kVideoSendSsrcs[0]);
oprypin6e09d872017-08-31 03:21:39 -0700117 return ssrc;
118}
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200119WEBRTC_DEFINE_string(ssrc, DefaultSsrc().c_str(), "Incoming SSRC");
oprypin6e09d872017-08-31 03:21:39 -0700120static uint32_t Ssrc() {
121 return rtc::StringToNumber<uint32_t>(FLAG_ssrc).value();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000122}
123
oprypin6e09d872017-08-31 03:21:39 -0700124const std::string& DefaultSsrcRtx() {
Yves Gerey665174f2018-06-19 15:03:05 +0200125 static const std::string ssrc_rtx =
126 std::to_string(test::CallTest::kSendRtxSsrcs[0]);
oprypin6e09d872017-08-31 03:21:39 -0700127 return ssrc_rtx;
128}
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200129WEBRTC_DEFINE_string(ssrc_rtx, DefaultSsrcRtx().c_str(), "Incoming RTX SSRC");
ilnik863f03b2017-07-11 02:38:36 -0700130static uint32_t SsrcRtx() {
oprypin6e09d872017-08-31 03:21:39 -0700131 return rtc::StringToNumber<uint32_t>(FLAG_ssrc_rtx).value();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000132}
133
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000134// Flag for abs-send-time id.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200135WEBRTC_DEFINE_int(abs_send_time_id, -1, "RTP extension ID for abs-send-time");
Yves Gerey665174f2018-06-19 15:03:05 +0200136static int AbsSendTimeId() {
137 return static_cast<int>(FLAG_abs_send_time_id);
138}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000139
140// Flag for transmission-offset id.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200141WEBRTC_DEFINE_int(transmission_offset_id,
142 -1,
143 "RTP extension ID for transmission-offset");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000144static int TransmissionOffsetId() {
oprypin6e09d872017-08-31 03:21:39 -0700145 return static_cast<int>(FLAG_transmission_offset_id);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000146}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000147
148// Flag for rtpdump input file.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200149WEBRTC_DEFINE_string(input_file, "", "input file");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000150static std::string InputFile() {
oprypin6e09d872017-08-31 03:21:39 -0700151 return static_cast<std::string>(FLAG_input_file);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000152}
153
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200154WEBRTC_DEFINE_string(config_file, "", "config file");
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700155static std::string ConfigFile() {
156 return static_cast<std::string>(FLAG_config_file);
157}
158
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000159// Flag for raw output files.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200160WEBRTC_DEFINE_string(out_base, "", "Basename (excluding .jpg) for raw output");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000161static std::string OutBase() {
oprypin6e09d872017-08-31 03:21:39 -0700162 return static_cast<std::string>(FLAG_out_base);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000163}
164
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200165WEBRTC_DEFINE_string(decoder_bitstream_filename,
166 "",
167 "Decoder bitstream output file");
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000168static std::string DecoderBitstreamFilename() {
oprypin6e09d872017-08-31 03:21:39 -0700169 return static_cast<std::string>(FLAG_decoder_bitstream_filename);
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000170}
171
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000172// Flag for video codec.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200173WEBRTC_DEFINE_string(codec, "VP8", "Video codec");
Yves Gerey665174f2018-06-19 15:03:05 +0200174static std::string Codec() {
175 return static_cast<std::string>(FLAG_codec);
176}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000177
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200178WEBRTC_DEFINE_bool(help, false, "Print this message.");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000179} // namespace flags
180
181static const uint32_t kReceiverLocalSsrc = 0x123456;
182
nisse7ade7b32016-03-23 04:48:10 -0700183class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000184 public:
nisse7ade7b32016-03-23 04:48:10 -0700185 FileRenderPassthrough(const std::string& basename,
186 rtc::VideoSinkInterface<VideoFrame>* renderer)
philipel99b63452017-08-25 07:24:21 -0700187 : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000188
Mirko Bonadeife055c12019-01-29 22:53:28 +0100189 ~FileRenderPassthrough() override {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200190 if (file_)
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000191 fclose(file_);
192 }
193
194 private:
nisseeb83a1a2016-03-21 01:27:56 -0700195 void OnFrame(const VideoFrame& video_frame) override {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200196 if (renderer_)
nisseeb83a1a2016-03-21 01:27:56 -0700197 renderer_->OnFrame(video_frame);
philipel99b63452017-08-25 07:24:21 -0700198
pbosbb36fdf2015-07-09 07:48:14 -0700199 if (basename_.empty())
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000200 return;
philipel99b63452017-08-25 07:24:21 -0700201
202 std::stringstream filename;
203 filename << basename_ << count_++ << "_" << video_frame.timestamp()
204 << ".jpg";
205
philipel99b63452017-08-25 07:24:21 -0700206 test::JpegFrameWriter frame_writer(filename.str());
207 RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000208 }
209
210 const std::string basename_;
nisse7ade7b32016-03-23 04:48:10 -0700211 rtc::VideoSinkInterface<VideoFrame>* const renderer_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000212 FILE* file_;
213 size_t count_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000214};
215
Niels Möllerf88a22c2018-06-19 17:05:03 +0200216class DecoderBitstreamFileWriter : public test::FakeDecoder {
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000217 public:
218 explicit DecoderBitstreamFileWriter(const char* filename)
219 : file_(fopen(filename, "wb")) {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200220 RTC_DCHECK(file_);
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000221 }
Mirko Bonadeife055c12019-01-29 22:53:28 +0100222 ~DecoderBitstreamFileWriter() override { fclose(file_); }
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000223
Niels Möllerf88a22c2018-06-19 17:05:03 +0200224 int32_t Decode(const EncodedImage& encoded_frame,
Benjamin Wright8efafdf2019-01-11 10:48:42 -0800225 bool /* missing_frames */,
226 const CodecSpecificInfo* /* codec_specific_info */,
227 int64_t /* render_time_ms */) override {
Niels Möller77536a22019-01-15 08:50:01 +0100228 if (fwrite(encoded_frame.data(), 1, encoded_frame.size(), file_) <
229 encoded_frame.size()) {
Niels Möllerf88a22c2018-06-19 17:05:03 +0200230 RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
231 return WEBRTC_VIDEO_CODEC_ERROR;
232 }
233 return WEBRTC_VIDEO_CODEC_OK;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000234 }
235
236 private:
237 FILE* file_;
238};
239
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700240// The RtpReplayer is responsible for parsing the configuration provided by the
241// user, setting up the windows, recieve streams and decoders and then replaying
242// the provided RTP dump.
243class RtpReplayer final {
244 public:
245 // Replay a rtp dump with an optional json configuration.
246 static void Replay(const std::string& replay_config_path,
247 const std::string& rtp_dump_path) {
248 webrtc::RtcEventLogNullImpl event_log;
249 Call::Config call_config(&event_log);
Mirko Bonadei05cf6be2019-01-31 21:38:12 +0100250 std::unique_ptr<Call> call(Call::Create(call_config));
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700251 std::unique_ptr<StreamState> stream_state;
252 // Attempt to load the configuration
253 if (replay_config_path.empty()) {
254 stream_state = ConfigureFromFlags(rtp_dump_path, call.get());
255 } else {
256 stream_state = ConfigureFromFile(replay_config_path, call.get());
257 }
258 if (stream_state == nullptr) {
259 return;
260 }
261 // Attempt to create an RtpReader from the input file.
262 std::unique_ptr<test::RtpFileReader> rtp_reader =
263 CreateRtpReader(rtp_dump_path);
264 if (rtp_reader == nullptr) {
265 return;
266 }
267 // Start replaying the provided stream now that it has been configured.
268 for (const auto& receive_stream : stream_state->receive_streams) {
269 receive_stream->Start();
270 }
271 ReplayPackets(call.get(), rtp_reader.get());
272 for (const auto& receive_stream : stream_state->receive_streams) {
273 call->DestroyVideoReceiveStream(receive_stream);
274 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000275 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000276
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700277 private:
278 // Holds all the shared memory structures required for a recieve stream. This
279 // structure is used to prevent members being deallocated before the replay
280 // has been finished.
281 struct StreamState {
282 test::NullTransport transport;
283 std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
284 std::vector<VideoReceiveStream*> receive_streams;
Niels Möllercbcbc222018-09-28 09:07:24 +0200285 std::unique_ptr<VideoDecoderFactory> decoder_factory;
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700286 };
287
288 // Loads multiple configurations from the provided configuration file.
289 static std::unique_ptr<StreamState> ConfigureFromFile(
290 const std::string& config_path,
291 Call* call) {
292 auto stream_state = absl::make_unique<StreamState>();
293 // Parse the configuration file.
294 std::ifstream config_file(config_path);
295 std::stringstream raw_json_buffer;
296 raw_json_buffer << config_file.rdbuf();
297 std::string raw_json = raw_json_buffer.str();
298 Json::Reader json_reader;
299 Json::Value json_configs;
300 if (!json_reader.parse(raw_json, json_configs)) {
301 fprintf(stderr, "Error parsing JSON config\n");
302 fprintf(stderr, "%s\n", json_reader.getFormatedErrorMessages().c_str());
303 return nullptr;
304 }
305
Niels Möllercbcbc222018-09-28 09:07:24 +0200306 stream_state->decoder_factory = absl::make_unique<InternalDecoderFactory>();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700307 size_t config_count = 0;
308 for (const auto& json : json_configs) {
309 // Create the configuration and parse the JSON into the config.
Benjamin Wright8efafdf2019-01-11 10:48:42 -0800310 auto receive_config =
311 ParseVideoReceiveStreamJsonConfig(&(stream_state->transport), json);
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700312 // Instantiate the underlying decoder.
313 for (auto& decoder : receive_config.decoders) {
Niels Möllercbcbc222018-09-28 09:07:24 +0200314 decoder = test::CreateMatchingDecoder(decoder.payload_type,
315 decoder.video_format.name);
316 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700317 }
318 // Create a window for this config.
319 std::stringstream window_title;
320 window_title << "Playback Video (" << config_count++ << ")";
321 stream_state->sinks.emplace_back(
322 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
323 // Create a receive stream for this config.
324 receive_config.renderer = stream_state->sinks.back().get();
325 stream_state->receive_streams.emplace_back(
326 call->CreateVideoReceiveStream(std::move(receive_config)));
327 }
328 return stream_state;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000329 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000330
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700331 // Loads the base configuration from flags passed in on the commandline.
332 static std::unique_ptr<StreamState> ConfigureFromFlags(
333 const std::string& rtp_dump_path,
334 Call* call) {
335 auto stream_state = absl::make_unique<StreamState>();
336 // Create the video renderers. We must add both to the stream state to keep
337 // them from deallocating.
338 std::stringstream window_title;
339 window_title << "Playback Video (" << rtp_dump_path << ")";
340 std::unique_ptr<test::VideoRenderer> playback_video(
341 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
342 auto file_passthrough = absl::make_unique<FileRenderPassthrough>(
343 flags::OutBase(), playback_video.get());
344 stream_state->sinks.push_back(std::move(playback_video));
345 stream_state->sinks.push_back(std::move(file_passthrough));
346 // Setup the configuration from the flags.
347 VideoReceiveStream::Config receive_config(&(stream_state->transport));
348 receive_config.rtp.remote_ssrc = flags::Ssrc();
349 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
350 receive_config.rtp.rtx_ssrc = flags::SsrcRtx();
351 receive_config.rtp
352 .rtx_associated_payload_types[flags::MediaPayloadTypeRtx()] =
353 flags::MediaPayloadType();
354 receive_config.rtp
355 .rtx_associated_payload_types[flags::RedPayloadTypeRtx()] =
356 flags::RedPayloadType();
357 receive_config.rtp.ulpfec_payload_type = flags::UlpfecPayloadType();
358 receive_config.rtp.red_payload_type = flags::RedPayloadType();
359 receive_config.rtp.nack.rtp_history_ms = 1000;
360 if (flags::TransmissionOffsetId() != -1) {
361 receive_config.rtp.extensions.push_back(RtpExtension(
362 RtpExtension::kTimestampOffsetUri, flags::TransmissionOffsetId()));
363 }
364 if (flags::AbsSendTimeId() != -1) {
365 receive_config.rtp.extensions.push_back(
366 RtpExtension(RtpExtension::kAbsSendTimeUri, flags::AbsSendTimeId()));
367 }
368 receive_config.renderer = stream_state->sinks.back().get();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000369
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700370 // Setup the receiving stream
371 VideoReceiveStream::Decoder decoder;
372 decoder =
373 test::CreateMatchingDecoder(flags::MediaPayloadType(), flags::Codec());
Niels Möllercbcbc222018-09-28 09:07:24 +0200374 if (flags::DecoderBitstreamFilename().empty()) {
375 stream_state->decoder_factory =
376 absl::make_unique<InternalDecoderFactory>();
377 } else {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700378 // Replace decoder with file writer if we're writing the bitstream to a
379 // file instead.
Niels Möllercbcbc222018-09-28 09:07:24 +0200380 stream_state->decoder_factory =
381 absl::make_unique<test::FunctionVideoDecoderFactory>([]() {
382 return absl::make_unique<DecoderBitstreamFileWriter>(
383 flags::DecoderBitstreamFilename().c_str());
384 });
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700385 }
Niels Möllercbcbc222018-09-28 09:07:24 +0200386 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700387 receive_config.decoders.push_back(decoder);
388
389 stream_state->receive_streams.emplace_back(
390 call->CreateVideoReceiveStream(std::move(receive_config)));
391 return stream_state;
392 }
393
394 static std::unique_ptr<test::RtpFileReader> CreateRtpReader(
395 const std::string& rtp_dump_path) {
396 std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
397 test::RtpFileReader::kRtpDump, rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200398 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700399 rtp_reader.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap,
400 rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200401 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700402 fprintf(
403 stderr,
404 "Couldn't open input file as either a rtpdump or .pcap. Note "
405 "that .pcapng is not supported.\nTrying to interpret the file as "
406 "length/packet interleaved.\n");
407 rtp_reader.reset(test::RtpFileReader::Create(
408 test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
409 if (!rtp_reader) {
410 fprintf(stderr,
411 "Unable to open input file with any supported format\n");
412 return nullptr;
413 }
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000414 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000415 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700416 return rtp_reader;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000417 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000418
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700419 static void ReplayPackets(Call* call, test::RtpFileReader* rtp_reader) {
420 int64_t replay_start_ms = -1;
421 int num_packets = 0;
422 std::map<uint32_t, int> unknown_packets;
423 while (true) {
424 int64_t now_ms = rtc::TimeMillis();
425 if (replay_start_ms == -1) {
426 replay_start_ms = now_ms;
427 }
philipel02f03962018-01-11 17:28:35 +0100428
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700429 test::RtpPacket packet;
430 if (!rtp_reader->NextPacket(&packet)) {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000431 break;
432 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700433
434 int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
435 if (deliver_in_ms > 0) {
436 SleepMs(deliver_in_ms);
437 }
438
439 ++num_packets;
440 switch (call->Receiver()->DeliverPacket(
441 webrtc::MediaType::VIDEO,
442 rtc::CopyOnWriteBuffer(packet.data, packet.length),
443 /* packet_time_us */ -1)) {
444 case PacketReceiver::DELIVERY_OK:
445 break;
446 case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
447 RTPHeader header;
448 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
449 parser->Parse(packet.data, packet.length, &header);
450 if (unknown_packets[header.ssrc] == 0)
451 fprintf(stderr, "Unknown SSRC: %u!\n", header.ssrc);
452 ++unknown_packets[header.ssrc];
453 break;
454 }
455 case PacketReceiver::DELIVERY_PACKET_ERROR: {
456 fprintf(stderr,
457 "Packet error, corrupt packets or incorrect setup?\n");
458 RTPHeader header;
459 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
460 parser->Parse(packet.data, packet.length, &header);
461 fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
462 packet.length, header.payloadType, header.sequenceNumber,
463 header.timestamp, header.ssrc);
464 break;
465 }
philipp.hancke7b589602017-01-26 04:54:04 -0800466 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000467 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700468 fprintf(stderr, "num_packets: %d\n", num_packets);
469
470 for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
471 it != unknown_packets.end(); ++it) {
472 fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
473 it->second);
474 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000475 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700476}; // class RtpReplayer
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000477
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700478void RtpReplay() {
479 RtpReplayer::Replay(flags::ConfigFile(), flags::InputFile());
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000480}
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700481
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000482} // namespace webrtc
483
484int main(int argc, char* argv[]) {
485 ::testing::InitGoogleTest(&argc, argv);
oprypin6e09d872017-08-31 03:21:39 -0700486 if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
487 return 1;
488 }
489 if (webrtc::flags::FLAG_help) {
490 rtc::FlagList::Print(nullptr, false);
491 return 0;
492 }
493
philipel752968e2017-12-05 12:40:28 +0100494 RTC_CHECK(ValidatePayloadType(webrtc::flags::FLAG_media_payload_type));
495 RTC_CHECK(ValidatePayloadType(webrtc::flags::FLAG_media_payload_type_rtx));
496 RTC_CHECK(ValidateOptionalPayloadType(webrtc::flags::FLAG_red_payload_type));
497 RTC_CHECK(
498 ValidateOptionalPayloadType(webrtc::flags::FLAG_red_payload_type_rtx));
499 RTC_CHECK(
500 ValidateOptionalPayloadType(webrtc::flags::FLAG_ulpfec_payload_type));
oprypin6e09d872017-08-31 03:21:39 -0700501 RTC_CHECK(ValidateSsrc(webrtc::flags::FLAG_ssrc));
502 RTC_CHECK(ValidateSsrc(webrtc::flags::FLAG_ssrc_rtx));
oprypin6e09d872017-08-31 03:21:39 -0700503 RTC_CHECK(ValidateRtpHeaderExtensionId(webrtc::flags::FLAG_abs_send_time_id));
Yves Gerey665174f2018-06-19 15:03:05 +0200504 RTC_CHECK(
505 ValidateRtpHeaderExtensionId(webrtc::flags::FLAG_transmission_offset_id));
oprypin6e09d872017-08-31 03:21:39 -0700506 RTC_CHECK(ValidateInputFilenameNotEmpty(webrtc::flags::FLAG_input_file));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000507
508 webrtc::test::RunTest(webrtc::RtpReplay);
509 return 0;
510}