• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
13 #include <fstream>
14 #include <map>
15 #include <memory>
16 
17 #include "absl/flags/flag.h"
18 #include "absl/flags/parse.h"
19 #include "api/rtc_event_log/rtc_event_log.h"
20 #include "api/task_queue/default_task_queue_factory.h"
21 #include "api/test/video/function_video_decoder_factory.h"
22 #include "api/transport/field_trial_based_config.h"
23 #include "api/video_codecs/video_decoder.h"
24 #include "call/call.h"
25 #include "common_video/libyuv/include/webrtc_libyuv.h"
26 #include "media/engine/internal_decoder_factory.h"
27 #include "rtc_base/checks.h"
28 #include "rtc_base/string_to_number.h"
29 #include "rtc_base/strings/json.h"
30 #include "rtc_base/time_utils.h"
31 #include "system_wrappers/include/clock.h"
32 #include "system_wrappers/include/sleep.h"
33 #include "test/call_config_utils.h"
34 #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/rtp_header_parser.h"
41 #include "test/run_loop.h"
42 #include "test/run_test.h"
43 #include "test/test_video_capturer.h"
44 #include "test/testsupport/frame_writer.h"
45 #include "test/video_renderer.h"
46 
47 // Flag for payload type.
48 ABSL_FLAG(int,
49           media_payload_type,
50           webrtc::test::CallTest::kPayloadTypeVP8,
51           "Media payload type");
52 
53 // Flag for RED payload type.
54 ABSL_FLAG(int,
55           red_payload_type,
56           webrtc::test::CallTest::kRedPayloadType,
57           "RED payload type");
58 
59 // Flag for ULPFEC payload type.
60 ABSL_FLAG(int,
61           ulpfec_payload_type,
62           webrtc::test::CallTest::kUlpfecPayloadType,
63           "ULPFEC payload type");
64 
65 ABSL_FLAG(int,
66           media_payload_type_rtx,
67           webrtc::test::CallTest::kSendRtxPayloadType,
68           "Media over RTX payload type");
69 
70 ABSL_FLAG(int,
71           red_payload_type_rtx,
72           webrtc::test::CallTest::kRtxRedPayloadType,
73           "RED over RTX payload type");
74 
75 // Flag for SSRC.
DefaultSsrc()76 const std::string& DefaultSsrc() {
77   static const std::string ssrc =
78       std::to_string(webrtc::test::CallTest::kVideoSendSsrcs[0]);
79   return ssrc;
80 }
81 ABSL_FLAG(std::string, ssrc, DefaultSsrc().c_str(), "Incoming SSRC");
82 
DefaultSsrcRtx()83 const std::string& DefaultSsrcRtx() {
84   static const std::string ssrc_rtx =
85       std::to_string(webrtc::test::CallTest::kSendRtxSsrcs[0]);
86   return ssrc_rtx;
87 }
88 ABSL_FLAG(std::string, ssrc_rtx, DefaultSsrcRtx().c_str(), "Incoming RTX SSRC");
89 
90 // Flag for abs-send-time id.
91 ABSL_FLAG(int, abs_send_time_id, -1, "RTP extension ID for abs-send-time");
92 
93 // Flag for transmission-offset id.
94 ABSL_FLAG(int,
95           transmission_offset_id,
96           -1,
97           "RTP extension ID for transmission-offset");
98 
99 // Flag for rtpdump input file.
100 ABSL_FLAG(std::string, input_file, "", "input file");
101 
102 ABSL_FLAG(std::string, config_file, "", "config file");
103 
104 // Flag for raw output files.
105 ABSL_FLAG(std::string,
106           out_base,
107           "",
108           "Basename (excluding .jpg) for raw output");
109 
110 ABSL_FLAG(std::string,
111           decoder_bitstream_filename,
112           "",
113           "Decoder bitstream output file");
114 
115 // Flag for video codec.
116 ABSL_FLAG(std::string, codec, "VP8", "Video codec");
117 
118 namespace {
119 
ValidatePayloadType(int32_t payload_type)120 static bool ValidatePayloadType(int32_t payload_type) {
121   return payload_type > 0 && payload_type <= 127;
122 }
123 
ValidateSsrc(const char * ssrc_string)124 static bool ValidateSsrc(const char* ssrc_string) {
125   return rtc::StringToNumber<uint32_t>(ssrc_string).has_value();
126 }
127 
ValidateOptionalPayloadType(int32_t payload_type)128 static bool ValidateOptionalPayloadType(int32_t payload_type) {
129   return payload_type == -1 || ValidatePayloadType(payload_type);
130 }
131 
ValidateRtpHeaderExtensionId(int32_t extension_id)132 static bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
133   return extension_id >= -1 && extension_id < 15;
134 }
135 
ValidateInputFilenameNotEmpty(const std::string & string)136 bool ValidateInputFilenameNotEmpty(const std::string& string) {
137   return !string.empty();
138 }
139 
MediaPayloadType()140 static int MediaPayloadType() {
141   return absl::GetFlag(FLAGS_media_payload_type);
142 }
143 
RedPayloadType()144 static int RedPayloadType() {
145   return absl::GetFlag(FLAGS_red_payload_type);
146 }
147 
UlpfecPayloadType()148 static int UlpfecPayloadType() {
149   return absl::GetFlag(FLAGS_ulpfec_payload_type);
150 }
151 
MediaPayloadTypeRtx()152 static int MediaPayloadTypeRtx() {
153   return absl::GetFlag(FLAGS_media_payload_type_rtx);
154 }
155 
RedPayloadTypeRtx()156 static int RedPayloadTypeRtx() {
157   return absl::GetFlag(FLAGS_red_payload_type_rtx);
158 }
159 
Ssrc()160 static uint32_t Ssrc() {
161   return rtc::StringToNumber<uint32_t>(absl::GetFlag(FLAGS_ssrc)).value();
162 }
163 
SsrcRtx()164 static uint32_t SsrcRtx() {
165   return rtc::StringToNumber<uint32_t>(absl::GetFlag(FLAGS_ssrc_rtx)).value();
166 }
167 
AbsSendTimeId()168 static int AbsSendTimeId() {
169   return absl::GetFlag(FLAGS_abs_send_time_id);
170 }
171 
TransmissionOffsetId()172 static int TransmissionOffsetId() {
173   return absl::GetFlag(FLAGS_transmission_offset_id);
174 }
175 
InputFile()176 static std::string InputFile() {
177   return absl::GetFlag(FLAGS_input_file);
178 }
179 
ConfigFile()180 static std::string ConfigFile() {
181   return absl::GetFlag(FLAGS_config_file);
182 }
183 
OutBase()184 static std::string OutBase() {
185   return absl::GetFlag(FLAGS_out_base);
186 }
187 
DecoderBitstreamFilename()188 static std::string DecoderBitstreamFilename() {
189   return absl::GetFlag(FLAGS_decoder_bitstream_filename);
190 }
191 
Codec()192 static std::string Codec() {
193   return absl::GetFlag(FLAGS_codec);
194 }
195 
196 }  // namespace
197 
198 namespace webrtc {
199 
200 static const uint32_t kReceiverLocalSsrc = 0x123456;
201 
202 class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
203  public:
FileRenderPassthrough(const std::string & basename,rtc::VideoSinkInterface<VideoFrame> * renderer)204   FileRenderPassthrough(const std::string& basename,
205                         rtc::VideoSinkInterface<VideoFrame>* renderer)
206       : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
207 
~FileRenderPassthrough()208   ~FileRenderPassthrough() override {
209     if (file_)
210       fclose(file_);
211   }
212 
213  private:
OnFrame(const VideoFrame & video_frame)214   void OnFrame(const VideoFrame& video_frame) override {
215     if (renderer_)
216       renderer_->OnFrame(video_frame);
217 
218     if (basename_.empty())
219       return;
220 
221     std::stringstream filename;
222     filename << basename_ << count_++ << "_" << video_frame.timestamp()
223              << ".jpg";
224 
225     test::JpegFrameWriter frame_writer(filename.str());
226     RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
227   }
228 
229   const std::string basename_;
230   rtc::VideoSinkInterface<VideoFrame>* const renderer_;
231   FILE* file_;
232   size_t count_;
233 };
234 
235 class DecoderBitstreamFileWriter : public test::FakeDecoder {
236  public:
DecoderBitstreamFileWriter(const char * filename)237   explicit DecoderBitstreamFileWriter(const char* filename)
238       : file_(fopen(filename, "wb")) {
239     RTC_DCHECK(file_);
240   }
~DecoderBitstreamFileWriter()241   ~DecoderBitstreamFileWriter() override { fclose(file_); }
242 
Decode(const EncodedImage & encoded_frame,bool,int64_t)243   int32_t Decode(const EncodedImage& encoded_frame,
244                  bool /* missing_frames */,
245                  int64_t /* render_time_ms */) override {
246     if (fwrite(encoded_frame.data(), 1, encoded_frame.size(), file_) <
247         encoded_frame.size()) {
248       RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
249       return WEBRTC_VIDEO_CODEC_ERROR;
250     }
251     return WEBRTC_VIDEO_CODEC_OK;
252   }
253 
254  private:
255   FILE* file_;
256 };
257 
258 // The RtpReplayer is responsible for parsing the configuration provided by the
259 // user, setting up the windows, recieve streams and decoders and then replaying
260 // the provided RTP dump.
261 class RtpReplayer final {
262  public:
263   // Replay a rtp dump with an optional json configuration.
Replay(const std::string & replay_config_path,const std::string & rtp_dump_path)264   static void Replay(const std::string& replay_config_path,
265                      const std::string& rtp_dump_path) {
266     std::unique_ptr<webrtc::TaskQueueFactory> task_queue_factory =
267         webrtc::CreateDefaultTaskQueueFactory();
268     webrtc::RtcEventLogNull event_log;
269     Call::Config call_config(&event_log);
270     call_config.task_queue_factory = task_queue_factory.get();
271     call_config.trials = new FieldTrialBasedConfig();
272     std::unique_ptr<Call> call(Call::Create(call_config));
273     std::unique_ptr<StreamState> stream_state;
274     // Attempt to load the configuration
275     if (replay_config_path.empty()) {
276       stream_state = ConfigureFromFlags(rtp_dump_path, call.get());
277     } else {
278       stream_state = ConfigureFromFile(replay_config_path, call.get());
279     }
280     if (stream_state == nullptr) {
281       return;
282     }
283     // Attempt to create an RtpReader from the input file.
284     std::unique_ptr<test::RtpFileReader> rtp_reader =
285         CreateRtpReader(rtp_dump_path);
286     if (rtp_reader == nullptr) {
287       return;
288     }
289     // Start replaying the provided stream now that it has been configured.
290     for (const auto& receive_stream : stream_state->receive_streams) {
291       receive_stream->Start();
292     }
293     ReplayPackets(call.get(), rtp_reader.get());
294     for (const auto& receive_stream : stream_state->receive_streams) {
295       call->DestroyVideoReceiveStream(receive_stream);
296     }
297   }
298 
299  private:
300   // Holds all the shared memory structures required for a recieve stream. This
301   // structure is used to prevent members being deallocated before the replay
302   // has been finished.
303   struct StreamState {
304     test::NullTransport transport;
305     std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
306     std::vector<VideoReceiveStream*> receive_streams;
307     std::unique_ptr<VideoDecoderFactory> decoder_factory;
308   };
309 
310   // Loads multiple configurations from the provided configuration file.
ConfigureFromFile(const std::string & config_path,Call * call)311   static std::unique_ptr<StreamState> ConfigureFromFile(
312       const std::string& config_path,
313       Call* call) {
314     auto stream_state = std::make_unique<StreamState>();
315     // Parse the configuration file.
316     std::ifstream config_file(config_path);
317     std::stringstream raw_json_buffer;
318     raw_json_buffer << config_file.rdbuf();
319     std::string raw_json = raw_json_buffer.str();
320     Json::Reader json_reader;
321     Json::Value json_configs;
322     if (!json_reader.parse(raw_json, json_configs)) {
323       fprintf(stderr, "Error parsing JSON config\n");
324       fprintf(stderr, "%s\n", json_reader.getFormatedErrorMessages().c_str());
325       return nullptr;
326     }
327 
328     stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
329     size_t config_count = 0;
330     for (const auto& json : json_configs) {
331       // Create the configuration and parse the JSON into the config.
332       auto receive_config =
333           ParseVideoReceiveStreamJsonConfig(&(stream_state->transport), json);
334       // Instantiate the underlying decoder.
335       for (auto& decoder : receive_config.decoders) {
336         decoder = test::CreateMatchingDecoder(decoder.payload_type,
337                                               decoder.video_format.name);
338         decoder.decoder_factory = stream_state->decoder_factory.get();
339       }
340       // Create a window for this config.
341       std::stringstream window_title;
342       window_title << "Playback Video (" << config_count++ << ")";
343       stream_state->sinks.emplace_back(
344           test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
345       // Create a receive stream for this config.
346       receive_config.renderer = stream_state->sinks.back().get();
347       stream_state->receive_streams.emplace_back(
348           call->CreateVideoReceiveStream(std::move(receive_config)));
349     }
350     return stream_state;
351   }
352 
353   // Loads the base configuration from flags passed in on the commandline.
ConfigureFromFlags(const std::string & rtp_dump_path,Call * call)354   static std::unique_ptr<StreamState> ConfigureFromFlags(
355       const std::string& rtp_dump_path,
356       Call* call) {
357     auto stream_state = std::make_unique<StreamState>();
358     // Create the video renderers. We must add both to the stream state to keep
359     // them from deallocating.
360     std::stringstream window_title;
361     window_title << "Playback Video (" << rtp_dump_path << ")";
362     std::unique_ptr<test::VideoRenderer> playback_video(
363         test::VideoRenderer::Create(window_title.str().c_str(), 640, 480));
364     auto file_passthrough = std::make_unique<FileRenderPassthrough>(
365         OutBase(), playback_video.get());
366     stream_state->sinks.push_back(std::move(playback_video));
367     stream_state->sinks.push_back(std::move(file_passthrough));
368     // Setup the configuration from the flags.
369     VideoReceiveStream::Config receive_config(&(stream_state->transport));
370     receive_config.rtp.remote_ssrc = Ssrc();
371     receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
372     receive_config.rtp.rtx_ssrc = SsrcRtx();
373     receive_config.rtp.rtx_associated_payload_types[MediaPayloadTypeRtx()] =
374         MediaPayloadType();
375     receive_config.rtp.rtx_associated_payload_types[RedPayloadTypeRtx()] =
376         RedPayloadType();
377     receive_config.rtp.ulpfec_payload_type = UlpfecPayloadType();
378     receive_config.rtp.red_payload_type = RedPayloadType();
379     receive_config.rtp.nack.rtp_history_ms = 1000;
380     if (TransmissionOffsetId() != -1) {
381       receive_config.rtp.extensions.push_back(RtpExtension(
382           RtpExtension::kTimestampOffsetUri, TransmissionOffsetId()));
383     }
384     if (AbsSendTimeId() != -1) {
385       receive_config.rtp.extensions.push_back(
386           RtpExtension(RtpExtension::kAbsSendTimeUri, AbsSendTimeId()));
387     }
388     receive_config.renderer = stream_state->sinks.back().get();
389 
390     // Setup the receiving stream
391     VideoReceiveStream::Decoder decoder;
392     decoder = test::CreateMatchingDecoder(MediaPayloadType(), Codec());
393     if (DecoderBitstreamFilename().empty()) {
394       stream_state->decoder_factory =
395           std::make_unique<InternalDecoderFactory>();
396     } else {
397       // Replace decoder with file writer if we're writing the bitstream to a
398       // file instead.
399       stream_state->decoder_factory =
400           std::make_unique<test::FunctionVideoDecoderFactory>([]() {
401             return std::make_unique<DecoderBitstreamFileWriter>(
402                 DecoderBitstreamFilename().c_str());
403           });
404     }
405     decoder.decoder_factory = stream_state->decoder_factory.get();
406     receive_config.decoders.push_back(decoder);
407 
408     stream_state->receive_streams.emplace_back(
409         call->CreateVideoReceiveStream(std::move(receive_config)));
410     return stream_state;
411   }
412 
CreateRtpReader(const std::string & rtp_dump_path)413   static std::unique_ptr<test::RtpFileReader> CreateRtpReader(
414       const std::string& rtp_dump_path) {
415     std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
416         test::RtpFileReader::kRtpDump, rtp_dump_path));
417     if (!rtp_reader) {
418       rtp_reader.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap,
419                                                    rtp_dump_path));
420       if (!rtp_reader) {
421         fprintf(
422             stderr,
423             "Couldn't open input file as either a rtpdump or .pcap. Note "
424             "that .pcapng is not supported.\nTrying to interpret the file as "
425             "length/packet interleaved.\n");
426         rtp_reader.reset(test::RtpFileReader::Create(
427             test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
428         if (!rtp_reader) {
429           fprintf(stderr,
430                   "Unable to open input file with any supported format\n");
431           return nullptr;
432         }
433       }
434     }
435     return rtp_reader;
436   }
437 
ReplayPackets(Call * call,test::RtpFileReader * rtp_reader)438   static void ReplayPackets(Call* call, test::RtpFileReader* rtp_reader) {
439     int64_t replay_start_ms = -1;
440     int num_packets = 0;
441     std::map<uint32_t, int> unknown_packets;
442     while (true) {
443       int64_t now_ms = rtc::TimeMillis();
444       if (replay_start_ms == -1) {
445         replay_start_ms = now_ms;
446       }
447 
448       test::RtpPacket packet;
449       if (!rtp_reader->NextPacket(&packet)) {
450         break;
451       }
452 
453       int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
454       if (deliver_in_ms > 0) {
455         SleepMs(deliver_in_ms);
456       }
457 
458       ++num_packets;
459       switch (call->Receiver()->DeliverPacket(
460           webrtc::MediaType::VIDEO,
461           rtc::CopyOnWriteBuffer(packet.data, packet.length),
462           /* packet_time_us */ -1)) {
463         case PacketReceiver::DELIVERY_OK:
464           break;
465         case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
466           RTPHeader header;
467           std::unique_ptr<RtpHeaderParser> parser(
468               RtpHeaderParser::CreateForTest());
469           parser->Parse(packet.data, packet.length, &header);
470           if (unknown_packets[header.ssrc] == 0)
471             fprintf(stderr, "Unknown SSRC: %u!\n", header.ssrc);
472           ++unknown_packets[header.ssrc];
473           break;
474         }
475         case PacketReceiver::DELIVERY_PACKET_ERROR: {
476           fprintf(stderr,
477                   "Packet error, corrupt packets or incorrect setup?\n");
478           RTPHeader header;
479           std::unique_ptr<RtpHeaderParser> parser(
480               RtpHeaderParser::CreateForTest());
481           parser->Parse(packet.data, packet.length, &header);
482           fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
483                   packet.length, header.payloadType, header.sequenceNumber,
484                   header.timestamp, header.ssrc);
485           break;
486         }
487       }
488     }
489     fprintf(stderr, "num_packets: %d\n", num_packets);
490 
491     for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
492          it != unknown_packets.end(); ++it) {
493       fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
494               it->second);
495     }
496   }
497 };  // class RtpReplayer
498 
RtpReplay()499 void RtpReplay() {
500   RtpReplayer::Replay(ConfigFile(), InputFile());
501 }
502 
503 }  // namespace webrtc
504 
main(int argc,char * argv[])505 int main(int argc, char* argv[]) {
506   ::testing::InitGoogleTest(&argc, argv);
507   absl::ParseCommandLine(argc, argv);
508 
509   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type)));
510   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type_rtx)));
511   RTC_CHECK(ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type)));
512   RTC_CHECK(
513       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type_rtx)));
514   RTC_CHECK(
515       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_ulpfec_payload_type)));
516   RTC_CHECK(ValidateSsrc(absl::GetFlag(FLAGS_ssrc).c_str()));
517   RTC_CHECK(ValidateSsrc(absl::GetFlag(FLAGS_ssrc_rtx).c_str()));
518   RTC_CHECK(
519       ValidateRtpHeaderExtensionId(absl::GetFlag(FLAGS_abs_send_time_id)));
520   RTC_CHECK(ValidateRtpHeaderExtensionId(
521       absl::GetFlag(FLAGS_transmission_offset_id)));
522   RTC_CHECK(ValidateInputFilenameNotEmpty(absl::GetFlag(FLAGS_input_file)));
523 
524   webrtc::test::RunTest(webrtc::RtpReplay);
525   return 0;
526 }
527