blob: 2c1c8a55ad4f5f8527cb162e8555d19b28acb649 [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#include <sstream>
17
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"
Niels Möllercbcbc222018-09-28 09:07:24 +020023#include "media/engine/internaldecoderfactory.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"
philipel02f03962018-01-11 17:28:35 +010030#include "rtc_base/timeutils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "system_wrappers/include/clock.h"
32#include "system_wrappers/include/sleep.h"
33#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"
39#include "test/run_loop.h"
40#include "test/run_test.h"
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020041#include "test/test_video_capturer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020042#include "test/testsupport/frame_writer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020043#include "test/video_renderer.h"
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000044
oprypin6e09d872017-08-31 03:21:39 -070045namespace {
46
47static bool ValidatePayloadType(int32_t payload_type) {
48 return payload_type > 0 && payload_type <= 127;
49}
50
51static bool ValidateSsrc(const char* ssrc_string) {
52 return rtc::StringToNumber<uint32_t>(ssrc_string).has_value();
53}
54
55static bool ValidateOptionalPayloadType(int32_t payload_type) {
56 return payload_type == -1 || ValidatePayloadType(payload_type);
57}
58
59static bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
60 return extension_id >= -1 && extension_id < 15;
61}
62
63bool ValidateInputFilenameNotEmpty(const std::string& string) {
64 return !string.empty();
65}
66
67} // namespace
68
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000069namespace webrtc {
70namespace flags {
71
72// TODO(pbos): Multiple receivers.
73
74// Flag for payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020075WEBRTC_DEFINE_int(media_payload_type,
76 test::CallTest::kPayloadTypeVP8,
77 "Media payload type");
philipel752968e2017-12-05 12:40:28 +010078static int MediaPayloadType() {
79 return static_cast<int>(FLAG_media_payload_type);
80}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +000081
philipel752968e2017-12-05 12:40:28 +010082// Flag for RED payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020083WEBRTC_DEFINE_int(red_payload_type,
84 test::CallTest::kRedPayloadType,
85 "RED payload type");
philipel752968e2017-12-05 12:40:28 +010086static int RedPayloadType() {
87 return static_cast<int>(FLAG_red_payload_type);
88}
89
90// Flag for ULPFEC payload type.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020091WEBRTC_DEFINE_int(ulpfec_payload_type,
92 test::CallTest::kUlpfecPayloadType,
93 "ULPFEC payload type");
philipel752968e2017-12-05 12:40:28 +010094static int UlpfecPayloadType() {
95 return static_cast<int>(FLAG_ulpfec_payload_type);
96}
97
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020098WEBRTC_DEFINE_int(media_payload_type_rtx,
99 test::CallTest::kSendRtxPayloadType,
100 "Media over RTX payload type");
philipel752968e2017-12-05 12:40:28 +0100101static int MediaPayloadTypeRtx() {
102 return static_cast<int>(FLAG_media_payload_type_rtx);
103}
104
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200105WEBRTC_DEFINE_int(red_payload_type_rtx,
106 test::CallTest::kRtxRedPayloadType,
107 "RED over RTX payload type");
philipel752968e2017-12-05 12:40:28 +0100108static int RedPayloadTypeRtx() {
109 return static_cast<int>(FLAG_red_payload_type_rtx);
ilnik863f03b2017-07-11 02:38:36 -0700110}
ilnik863f03b2017-07-11 02:38:36 -0700111
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000112// Flag for SSRC.
oprypin6e09d872017-08-31 03:21:39 -0700113const std::string& DefaultSsrc() {
Yves Gerey665174f2018-06-19 15:03:05 +0200114 static const std::string ssrc =
115 std::to_string(test::CallTest::kVideoSendSsrcs[0]);
oprypin6e09d872017-08-31 03:21:39 -0700116 return ssrc;
117}
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200118WEBRTC_DEFINE_string(ssrc, DefaultSsrc().c_str(), "Incoming SSRC");
oprypin6e09d872017-08-31 03:21:39 -0700119static uint32_t Ssrc() {
120 return rtc::StringToNumber<uint32_t>(FLAG_ssrc).value();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000121}
122
oprypin6e09d872017-08-31 03:21:39 -0700123const std::string& DefaultSsrcRtx() {
Yves Gerey665174f2018-06-19 15:03:05 +0200124 static const std::string ssrc_rtx =
125 std::to_string(test::CallTest::kSendRtxSsrcs[0]);
oprypin6e09d872017-08-31 03:21:39 -0700126 return ssrc_rtx;
127}
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200128WEBRTC_DEFINE_string(ssrc_rtx, DefaultSsrcRtx().c_str(), "Incoming RTX SSRC");
ilnik863f03b2017-07-11 02:38:36 -0700129static uint32_t SsrcRtx() {
oprypin6e09d872017-08-31 03:21:39 -0700130 return rtc::StringToNumber<uint32_t>(FLAG_ssrc_rtx).value();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000131}
132
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000133// Flag for abs-send-time id.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200134WEBRTC_DEFINE_int(abs_send_time_id, -1, "RTP extension ID for abs-send-time");
Yves Gerey665174f2018-06-19 15:03:05 +0200135static int AbsSendTimeId() {
136 return static_cast<int>(FLAG_abs_send_time_id);
137}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000138
139// Flag for transmission-offset id.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200140WEBRTC_DEFINE_int(transmission_offset_id,
141 -1,
142 "RTP extension ID for transmission-offset");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000143static int TransmissionOffsetId() {
oprypin6e09d872017-08-31 03:21:39 -0700144 return static_cast<int>(FLAG_transmission_offset_id);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000145}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000146
147// Flag for rtpdump input file.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200148WEBRTC_DEFINE_string(input_file, "", "input file");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000149static std::string InputFile() {
oprypin6e09d872017-08-31 03:21:39 -0700150 return static_cast<std::string>(FLAG_input_file);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000151}
152
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200153WEBRTC_DEFINE_string(config_file, "", "config file");
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700154static std::string ConfigFile() {
155 return static_cast<std::string>(FLAG_config_file);
156}
157
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000158// Flag for raw output files.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200159WEBRTC_DEFINE_string(out_base, "", "Basename (excluding .jpg) for raw output");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000160static std::string OutBase() {
oprypin6e09d872017-08-31 03:21:39 -0700161 return static_cast<std::string>(FLAG_out_base);
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000162}
163
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200164WEBRTC_DEFINE_string(decoder_bitstream_filename,
165 "",
166 "Decoder bitstream output file");
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000167static std::string DecoderBitstreamFilename() {
oprypin6e09d872017-08-31 03:21:39 -0700168 return static_cast<std::string>(FLAG_decoder_bitstream_filename);
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000169}
170
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000171// Flag for video codec.
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200172WEBRTC_DEFINE_string(codec, "VP8", "Video codec");
Yves Gerey665174f2018-06-19 15:03:05 +0200173static std::string Codec() {
174 return static_cast<std::string>(FLAG_codec);
175}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000176
Mirko Bonadei2dfa9982018-10-18 11:35:32 +0200177WEBRTC_DEFINE_bool(help, false, "Print this message.");
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000178} // namespace flags
179
180static const uint32_t kReceiverLocalSsrc = 0x123456;
181
nisse7ade7b32016-03-23 04:48:10 -0700182class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000183 public:
nisse7ade7b32016-03-23 04:48:10 -0700184 FileRenderPassthrough(const std::string& basename,
185 rtc::VideoSinkInterface<VideoFrame>* renderer)
philipel99b63452017-08-25 07:24:21 -0700186 : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000187
188 ~FileRenderPassthrough() {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200189 if (file_)
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000190 fclose(file_);
191 }
192
193 private:
nisseeb83a1a2016-03-21 01:27:56 -0700194 void OnFrame(const VideoFrame& video_frame) override {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200195 if (renderer_)
nisseeb83a1a2016-03-21 01:27:56 -0700196 renderer_->OnFrame(video_frame);
philipel99b63452017-08-25 07:24:21 -0700197
pbosbb36fdf2015-07-09 07:48:14 -0700198 if (basename_.empty())
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000199 return;
philipel99b63452017-08-25 07:24:21 -0700200
201 std::stringstream filename;
202 filename << basename_ << count_++ << "_" << video_frame.timestamp()
203 << ".jpg";
204
philipel99b63452017-08-25 07:24:21 -0700205 test::JpegFrameWriter frame_writer(filename.str());
206 RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000207 }
208
209 const std::string basename_;
nisse7ade7b32016-03-23 04:48:10 -0700210 rtc::VideoSinkInterface<VideoFrame>* const renderer_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000211 FILE* file_;
212 size_t count_;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000213};
214
Niels Möllerf88a22c2018-06-19 17:05:03 +0200215class DecoderBitstreamFileWriter : public test::FakeDecoder {
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000216 public:
217 explicit DecoderBitstreamFileWriter(const char* filename)
218 : file_(fopen(filename, "wb")) {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200219 RTC_DCHECK(file_);
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000220 }
221 ~DecoderBitstreamFileWriter() { fclose(file_); }
222
Niels Möllerf88a22c2018-06-19 17:05:03 +0200223 int32_t Decode(const EncodedImage& encoded_frame,
224 bool /* missing_frames */,
225 const CodecSpecificInfo* /* codec_specific_info */,
226 int64_t /* render_time_ms */) override {
227 if (fwrite(encoded_frame._buffer, 1, encoded_frame._length, file_)
228 < encoded_frame._length) {
229 RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
230 return WEBRTC_VIDEO_CODEC_ERROR;
231 }
232 return WEBRTC_VIDEO_CODEC_OK;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000233 }
234
235 private:
236 FILE* file_;
237};
238
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700239// Deserializes a JSON representation of the VideoReceiveStream::Config back
240// into a valid object. This will not initialize the decoders or the renderer.
241class VideoReceiveStreamConfigDeserializer final {
242 public:
243 static VideoReceiveStream::Config Deserialize(webrtc::Transport* transport,
244 const Json::Value& json) {
245 auto receive_config = VideoReceiveStream::Config(transport);
246 for (const auto decoder_json : json["decoders"]) {
247 VideoReceiveStream::Decoder decoder;
Niels Möllercb7e1d22018-09-11 15:56:04 +0200248 decoder.video_format =
249 SdpVideoFormat(decoder_json["payload_name"].asString());
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700250 decoder.payload_type = decoder_json["payload_type"].asInt64();
251 for (const auto& params_json : decoder_json["codec_params"]) {
252 std::vector<std::string> members = params_json.getMemberNames();
253 RTC_CHECK_EQ(members.size(), 1);
Niels Möllercb7e1d22018-09-11 15:56:04 +0200254 decoder.video_format.parameters[members[0]] =
255 params_json[members[0]].asString();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700256 }
257 receive_config.decoders.push_back(decoder);
258 }
259 receive_config.render_delay_ms = json["render_delay_ms"].asInt64();
260 receive_config.target_delay_ms = json["target_delay_ms"].asInt64();
261 receive_config.rtp.remote_ssrc = json["remote_ssrc"].asInt64();
262 receive_config.rtp.local_ssrc = json["local_ssrc"].asInt64();
263 receive_config.rtp.rtcp_mode =
264 json["rtcp_mode"].asString() == "RtcpMode::kCompound"
265 ? RtcpMode::kCompound
266 : RtcpMode::kReducedSize;
267 receive_config.rtp.remb = json["remb"].asBool();
268 receive_config.rtp.transport_cc = json["transport_cc"].asBool();
269 receive_config.rtp.nack.rtp_history_ms =
270 json["nack"]["rtp_history_ms"].asInt64();
271 receive_config.rtp.ulpfec_payload_type =
272 json["ulpfec_payload_type"].asInt64();
273 receive_config.rtp.red_payload_type = json["red_payload_type"].asInt64();
274 receive_config.rtp.rtx_ssrc = json["rtx_ssrc"].asInt64();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000275
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700276 for (const auto& pl_json : json["rtx_payload_types"]) {
277 std::vector<std::string> members = pl_json.getMemberNames();
278 RTC_CHECK_EQ(members.size(), 1);
279 Json::Value rtx_payload_type = pl_json[members[0]];
280 receive_config.rtp.rtx_associated_payload_types[std::stoi(members[0])] =
281 rtx_payload_type.asInt64();
282 }
283 for (const auto& ext_json : json["extensions"]) {
284 receive_config.rtp.extensions.emplace_back(ext_json["uri"].asString(),
285 ext_json["id"].asInt64(),
286 ext_json["encrypt"].asBool());
287 }
288 return receive_config;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000289 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700290};
291
292// The RtpReplayer is responsible for parsing the configuration provided by the
293// user, setting up the windows, recieve streams and decoders and then replaying
294// the provided RTP dump.
295class RtpReplayer final {
296 public:
297 // Replay a rtp dump with an optional json configuration.
298 static void Replay(const std::string& replay_config_path,
299 const std::string& rtp_dump_path) {
300 webrtc::RtcEventLogNullImpl event_log;
301 Call::Config call_config(&event_log);
302 std::unique_ptr<Call> call(Call::Create(std::move(call_config)));
303 std::unique_ptr<StreamState> stream_state;
304 // Attempt to load the configuration
305 if (replay_config_path.empty()) {
306 stream_state = ConfigureFromFlags(rtp_dump_path, call.get());
307 } else {
308 stream_state = ConfigureFromFile(replay_config_path, call.get());
309 }
310 if (stream_state == nullptr) {
311 return;
312 }
313 // Attempt to create an RtpReader from the input file.
314 std::unique_ptr<test::RtpFileReader> rtp_reader =
315 CreateRtpReader(rtp_dump_path);
316 if (rtp_reader == nullptr) {
317 return;
318 }
319 // Start replaying the provided stream now that it has been configured.
320 for (const auto& receive_stream : stream_state->receive_streams) {
321 receive_stream->Start();
322 }
323 ReplayPackets(call.get(), rtp_reader.get());
324 for (const auto& receive_stream : stream_state->receive_streams) {
325 call->DestroyVideoReceiveStream(receive_stream);
326 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000327 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000328
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700329 private:
330 // Holds all the shared memory structures required for a recieve stream. This
331 // structure is used to prevent members being deallocated before the replay
332 // has been finished.
333 struct StreamState {
334 test::NullTransport transport;
335 std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
336 std::vector<VideoReceiveStream*> receive_streams;
Niels Möllercbcbc222018-09-28 09:07:24 +0200337 std::unique_ptr<VideoDecoderFactory> decoder_factory;
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700338 };
339
340 // Loads multiple configurations from the provided configuration file.
341 static std::unique_ptr<StreamState> ConfigureFromFile(
342 const std::string& config_path,
343 Call* call) {
344 auto stream_state = absl::make_unique<StreamState>();
345 // Parse the configuration file.
346 std::ifstream config_file(config_path);
347 std::stringstream raw_json_buffer;
348 raw_json_buffer << config_file.rdbuf();
349 std::string raw_json = raw_json_buffer.str();
350 Json::Reader json_reader;
351 Json::Value json_configs;
352 if (!json_reader.parse(raw_json, json_configs)) {
353 fprintf(stderr, "Error parsing JSON config\n");
354 fprintf(stderr, "%s\n", json_reader.getFormatedErrorMessages().c_str());
355 return nullptr;
356 }
357
Niels Möllercbcbc222018-09-28 09:07:24 +0200358 stream_state->decoder_factory = absl::make_unique<InternalDecoderFactory>();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700359 size_t config_count = 0;
360 for (const auto& json : json_configs) {
361 // Create the configuration and parse the JSON into the config.
362 auto receive_config = VideoReceiveStreamConfigDeserializer::Deserialize(
363 &(stream_state->transport), json);
364 // Instantiate the underlying decoder.
365 for (auto& decoder : receive_config.decoders) {
Niels Möllercbcbc222018-09-28 09:07:24 +0200366 decoder = test::CreateMatchingDecoder(decoder.payload_type,
367 decoder.video_format.name);
368 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700369 }
370 // Create a window for this config.
371 std::stringstream window_title;
372 window_title << "Playback Video (" << config_count++ << ")";
373 stream_state->sinks.emplace_back(
374 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
375 // Create a receive stream for this config.
376 receive_config.renderer = stream_state->sinks.back().get();
377 stream_state->receive_streams.emplace_back(
378 call->CreateVideoReceiveStream(std::move(receive_config)));
379 }
380 return stream_state;
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000381 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000382
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700383 // Loads the base configuration from flags passed in on the commandline.
384 static std::unique_ptr<StreamState> ConfigureFromFlags(
385 const std::string& rtp_dump_path,
386 Call* call) {
387 auto stream_state = absl::make_unique<StreamState>();
388 // Create the video renderers. We must add both to the stream state to keep
389 // them from deallocating.
390 std::stringstream window_title;
391 window_title << "Playback Video (" << rtp_dump_path << ")";
392 std::unique_ptr<test::VideoRenderer> playback_video(
393 test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
394 auto file_passthrough = absl::make_unique<FileRenderPassthrough>(
395 flags::OutBase(), playback_video.get());
396 stream_state->sinks.push_back(std::move(playback_video));
397 stream_state->sinks.push_back(std::move(file_passthrough));
398 // Setup the configuration from the flags.
399 VideoReceiveStream::Config receive_config(&(stream_state->transport));
400 receive_config.rtp.remote_ssrc = flags::Ssrc();
401 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
402 receive_config.rtp.rtx_ssrc = flags::SsrcRtx();
403 receive_config.rtp
404 .rtx_associated_payload_types[flags::MediaPayloadTypeRtx()] =
405 flags::MediaPayloadType();
406 receive_config.rtp
407 .rtx_associated_payload_types[flags::RedPayloadTypeRtx()] =
408 flags::RedPayloadType();
409 receive_config.rtp.ulpfec_payload_type = flags::UlpfecPayloadType();
410 receive_config.rtp.red_payload_type = flags::RedPayloadType();
411 receive_config.rtp.nack.rtp_history_ms = 1000;
412 if (flags::TransmissionOffsetId() != -1) {
413 receive_config.rtp.extensions.push_back(RtpExtension(
414 RtpExtension::kTimestampOffsetUri, flags::TransmissionOffsetId()));
415 }
416 if (flags::AbsSendTimeId() != -1) {
417 receive_config.rtp.extensions.push_back(
418 RtpExtension(RtpExtension::kAbsSendTimeUri, flags::AbsSendTimeId()));
419 }
420 receive_config.renderer = stream_state->sinks.back().get();
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000421
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700422 // Setup the receiving stream
423 VideoReceiveStream::Decoder decoder;
424 decoder =
425 test::CreateMatchingDecoder(flags::MediaPayloadType(), flags::Codec());
Niels Möllercbcbc222018-09-28 09:07:24 +0200426 if (flags::DecoderBitstreamFilename().empty()) {
427 stream_state->decoder_factory =
428 absl::make_unique<InternalDecoderFactory>();
429 } else {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700430 // Replace decoder with file writer if we're writing the bitstream to a
431 // file instead.
Niels Möllercbcbc222018-09-28 09:07:24 +0200432 stream_state->decoder_factory =
433 absl::make_unique<test::FunctionVideoDecoderFactory>([]() {
434 return absl::make_unique<DecoderBitstreamFileWriter>(
435 flags::DecoderBitstreamFilename().c_str());
436 });
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700437 }
Niels Möllercbcbc222018-09-28 09:07:24 +0200438 decoder.decoder_factory = stream_state->decoder_factory.get();
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700439 receive_config.decoders.push_back(decoder);
440
441 stream_state->receive_streams.emplace_back(
442 call->CreateVideoReceiveStream(std::move(receive_config)));
443 return stream_state;
444 }
445
446 static std::unique_ptr<test::RtpFileReader> CreateRtpReader(
447 const std::string& rtp_dump_path) {
448 std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
449 test::RtpFileReader::kRtpDump, rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200450 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700451 rtp_reader.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap,
452 rtp_dump_path));
Peter Boström74f6e9e2016-04-04 17:56:10 +0200453 if (!rtp_reader) {
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700454 fprintf(
455 stderr,
456 "Couldn't open input file as either a rtpdump or .pcap. Note "
457 "that .pcapng is not supported.\nTrying to interpret the file as "
458 "length/packet interleaved.\n");
459 rtp_reader.reset(test::RtpFileReader::Create(
460 test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
461 if (!rtp_reader) {
462 fprintf(stderr,
463 "Unable to open input file with any supported format\n");
464 return nullptr;
465 }
stefan@webrtc.org48ac2262015-03-02 16:18:56 +0000466 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000467 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700468 return rtp_reader;
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000469 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000470
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700471 static void ReplayPackets(Call* call, test::RtpFileReader* rtp_reader) {
472 int64_t replay_start_ms = -1;
473 int num_packets = 0;
474 std::map<uint32_t, int> unknown_packets;
475 while (true) {
476 int64_t now_ms = rtc::TimeMillis();
477 if (replay_start_ms == -1) {
478 replay_start_ms = now_ms;
479 }
philipel02f03962018-01-11 17:28:35 +0100480
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700481 test::RtpPacket packet;
482 if (!rtp_reader->NextPacket(&packet)) {
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000483 break;
484 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700485
486 int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
487 if (deliver_in_ms > 0) {
488 SleepMs(deliver_in_ms);
489 }
490
491 ++num_packets;
492 switch (call->Receiver()->DeliverPacket(
493 webrtc::MediaType::VIDEO,
494 rtc::CopyOnWriteBuffer(packet.data, packet.length),
495 /* packet_time_us */ -1)) {
496 case PacketReceiver::DELIVERY_OK:
497 break;
498 case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
499 RTPHeader header;
500 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
501 parser->Parse(packet.data, packet.length, &header);
502 if (unknown_packets[header.ssrc] == 0)
503 fprintf(stderr, "Unknown SSRC: %u!\n", header.ssrc);
504 ++unknown_packets[header.ssrc];
505 break;
506 }
507 case PacketReceiver::DELIVERY_PACKET_ERROR: {
508 fprintf(stderr,
509 "Packet error, corrupt packets or incorrect setup?\n");
510 RTPHeader header;
511 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
512 parser->Parse(packet.data, packet.length, &header);
513 fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
514 packet.length, header.payloadType, header.sequenceNumber,
515 header.timestamp, header.ssrc);
516 break;
517 }
philipp.hancke7b589602017-01-26 04:54:04 -0800518 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000519 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700520 fprintf(stderr, "num_packets: %d\n", num_packets);
521
522 for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
523 it != unknown_packets.end(); ++it) {
524 fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
525 it->second);
526 }
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000527 }
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700528}; // class RtpReplayer
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000529
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700530void RtpReplay() {
531 RtpReplayer::Replay(flags::ConfigFile(), flags::InputFile());
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000532}
Benjamin Wright90ab76d2018-08-23 11:33:29 -0700533
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000534} // namespace webrtc
535
536int main(int argc, char* argv[]) {
537 ::testing::InitGoogleTest(&argc, argv);
oprypin6e09d872017-08-31 03:21:39 -0700538 if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
539 return 1;
540 }
541 if (webrtc::flags::FLAG_help) {
542 rtc::FlagList::Print(nullptr, false);
543 return 0;
544 }
545
philipel752968e2017-12-05 12:40:28 +0100546 RTC_CHECK(ValidatePayloadType(webrtc::flags::FLAG_media_payload_type));
547 RTC_CHECK(ValidatePayloadType(webrtc::flags::FLAG_media_payload_type_rtx));
548 RTC_CHECK(ValidateOptionalPayloadType(webrtc::flags::FLAG_red_payload_type));
549 RTC_CHECK(
550 ValidateOptionalPayloadType(webrtc::flags::FLAG_red_payload_type_rtx));
551 RTC_CHECK(
552 ValidateOptionalPayloadType(webrtc::flags::FLAG_ulpfec_payload_type));
oprypin6e09d872017-08-31 03:21:39 -0700553 RTC_CHECK(ValidateSsrc(webrtc::flags::FLAG_ssrc));
554 RTC_CHECK(ValidateSsrc(webrtc::flags::FLAG_ssrc_rtx));
oprypin6e09d872017-08-31 03:21:39 -0700555 RTC_CHECK(ValidateRtpHeaderExtensionId(webrtc::flags::FLAG_abs_send_time_id));
Yves Gerey665174f2018-06-19 15:03:05 +0200556 RTC_CHECK(
557 ValidateRtpHeaderExtensionId(webrtc::flags::FLAG_transmission_offset_id));
oprypin6e09d872017-08-31 03:21:39 -0700558 RTC_CHECK(ValidateInputFilenameNotEmpty(webrtc::flags::FLAG_input_file));
pbos@webrtc.org4b5625e2014-08-06 16:26:56 +0000559
560 webrtc::test::RunTest(webrtc::RtpReplay);
561 return 0;
562}