xref: /aosp_15_r20/external/webrtc/rtc_tools/video_replay.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include <stdio.h>
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <fstream>
14*d9f75844SAndroid Build Coastguard Worker #include <map>
15*d9f75844SAndroid Build Coastguard Worker #include <memory>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "absl/flags/flag.h"
18*d9f75844SAndroid Build Coastguard Worker #include "absl/flags/parse.h"
19*d9f75844SAndroid Build Coastguard Worker #include "api/field_trials.h"
20*d9f75844SAndroid Build Coastguard Worker #include "api/rtc_event_log/rtc_event_log.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/default_task_queue_factory.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/test/video/function_video_decoder_factory.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/transport/field_trial_based_config.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_codec_type.h"
25*d9f75844SAndroid Build Coastguard Worker #include "api/video_codecs/video_decoder.h"
26*d9f75844SAndroid Build Coastguard Worker #include "call/call.h"
27*d9f75844SAndroid Build Coastguard Worker #include "common_video/libyuv/include/webrtc_libyuv.h"
28*d9f75844SAndroid Build Coastguard Worker #include "media/engine/internal_decoder_factory.h"
29*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_packet.h"
30*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_util.h"
31*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/utility/ivf_file_writer.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/string_to_number.h"
34*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/json.h"
35*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
36*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
37*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/sleep.h"
38*d9f75844SAndroid Build Coastguard Worker #include "test/call_config_utils.h"
39*d9f75844SAndroid Build Coastguard Worker #include "test/call_test.h"
40*d9f75844SAndroid Build Coastguard Worker #include "test/encoder_settings.h"
41*d9f75844SAndroid Build Coastguard Worker #include "test/fake_decoder.h"
42*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
43*d9f75844SAndroid Build Coastguard Worker #include "test/null_transport.h"
44*d9f75844SAndroid Build Coastguard Worker #include "test/rtp_file_reader.h"
45*d9f75844SAndroid Build Coastguard Worker #include "test/run_loop.h"
46*d9f75844SAndroid Build Coastguard Worker #include "test/run_test.h"
47*d9f75844SAndroid Build Coastguard Worker #include "test/test_video_capturer.h"
48*d9f75844SAndroid Build Coastguard Worker #include "test/testsupport/frame_writer.h"
49*d9f75844SAndroid Build Coastguard Worker #include "test/time_controller/simulated_time_controller.h"
50*d9f75844SAndroid Build Coastguard Worker #include "test/video_renderer.h"
51*d9f75844SAndroid Build Coastguard Worker 
52*d9f75844SAndroid Build Coastguard Worker // Flag for payload type.
53*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
54*d9f75844SAndroid Build Coastguard Worker           media_payload_type,
55*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kPayloadTypeVP8,
56*d9f75844SAndroid Build Coastguard Worker           "Media payload type");
57*d9f75844SAndroid Build Coastguard Worker 
58*d9f75844SAndroid Build Coastguard Worker // Flag for RED payload type.
59*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
60*d9f75844SAndroid Build Coastguard Worker           red_payload_type,
61*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kRedPayloadType,
62*d9f75844SAndroid Build Coastguard Worker           "RED payload type");
63*d9f75844SAndroid Build Coastguard Worker 
64*d9f75844SAndroid Build Coastguard Worker // Flag for ULPFEC payload type.
65*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
66*d9f75844SAndroid Build Coastguard Worker           ulpfec_payload_type,
67*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kUlpfecPayloadType,
68*d9f75844SAndroid Build Coastguard Worker           "ULPFEC payload type");
69*d9f75844SAndroid Build Coastguard Worker 
70*d9f75844SAndroid Build Coastguard Worker // Flag for FLEXFEC payload type.
71*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
72*d9f75844SAndroid Build Coastguard Worker           flexfec_payload_type,
73*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kFlexfecPayloadType,
74*d9f75844SAndroid Build Coastguard Worker           "FLEXFEC payload type");
75*d9f75844SAndroid Build Coastguard Worker 
76*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
77*d9f75844SAndroid Build Coastguard Worker           media_payload_type_rtx,
78*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kSendRtxPayloadType,
79*d9f75844SAndroid Build Coastguard Worker           "Media over RTX payload type");
80*d9f75844SAndroid Build Coastguard Worker 
81*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
82*d9f75844SAndroid Build Coastguard Worker           red_payload_type_rtx,
83*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kRtxRedPayloadType,
84*d9f75844SAndroid Build Coastguard Worker           "RED over RTX payload type");
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker // Flag for SSRC and RTX SSRC.
87*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t,
88*d9f75844SAndroid Build Coastguard Worker           ssrc,
89*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kVideoSendSsrcs[0],
90*d9f75844SAndroid Build Coastguard Worker           "Incoming SSRC");
91*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t,
92*d9f75844SAndroid Build Coastguard Worker           ssrc_rtx,
93*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kSendRtxSsrcs[0],
94*d9f75844SAndroid Build Coastguard Worker           "Incoming RTX SSRC");
95*d9f75844SAndroid Build Coastguard Worker 
96*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t,
97*d9f75844SAndroid Build Coastguard Worker           ssrc_flexfec,
98*d9f75844SAndroid Build Coastguard Worker           webrtc::test::CallTest::kFlexfecSendSsrc,
99*d9f75844SAndroid Build Coastguard Worker           "Incoming FLEXFEC SSRC");
100*d9f75844SAndroid Build Coastguard Worker 
101*d9f75844SAndroid Build Coastguard Worker // Flag for abs-send-time id.
102*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int, abs_send_time_id, -1, "RTP extension ID for abs-send-time");
103*d9f75844SAndroid Build Coastguard Worker 
104*d9f75844SAndroid Build Coastguard Worker // Flag for transmission-offset id.
105*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
106*d9f75844SAndroid Build Coastguard Worker           transmission_offset_id,
107*d9f75844SAndroid Build Coastguard Worker           -1,
108*d9f75844SAndroid Build Coastguard Worker           "RTP extension ID for transmission-offset");
109*d9f75844SAndroid Build Coastguard Worker 
110*d9f75844SAndroid Build Coastguard Worker // Flag for rtpdump input file.
111*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string, input_file, "", "input file");
112*d9f75844SAndroid Build Coastguard Worker 
113*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string, config_file, "", "config file");
114*d9f75844SAndroid Build Coastguard Worker 
115*d9f75844SAndroid Build Coastguard Worker // Flag for raw output files.
116*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string,
117*d9f75844SAndroid Build Coastguard Worker           out_base,
118*d9f75844SAndroid Build Coastguard Worker           "",
119*d9f75844SAndroid Build Coastguard Worker           "Basename (excluding .jpg) for raw output");
120*d9f75844SAndroid Build Coastguard Worker 
121*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string,
122*d9f75844SAndroid Build Coastguard Worker           decoder_bitstream_filename,
123*d9f75844SAndroid Build Coastguard Worker           "",
124*d9f75844SAndroid Build Coastguard Worker           "Decoder bitstream output file");
125*d9f75844SAndroid Build Coastguard Worker 
126*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string, decoder_ivf_filename, "", "Decoder ivf output file");
127*d9f75844SAndroid Build Coastguard Worker 
128*d9f75844SAndroid Build Coastguard Worker // Flag for video codec.
129*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(std::string, codec, "VP8", "Video codec");
130*d9f75844SAndroid Build Coastguard Worker 
131*d9f75844SAndroid Build Coastguard Worker // Flags for rtp start and stop timestamp.
132*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t,
133*d9f75844SAndroid Build Coastguard Worker           start_timestamp,
134*d9f75844SAndroid Build Coastguard Worker           0,
135*d9f75844SAndroid Build Coastguard Worker           "RTP start timestamp, packets with smaller timestamp will be ignored "
136*d9f75844SAndroid Build Coastguard Worker           "(no wraparound)");
137*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t,
138*d9f75844SAndroid Build Coastguard Worker           stop_timestamp,
139*d9f75844SAndroid Build Coastguard Worker           4294967295,
140*d9f75844SAndroid Build Coastguard Worker           "RTP stop timestamp, packets with larger timestamp will be ignored "
141*d9f75844SAndroid Build Coastguard Worker           "(no wraparound)");
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker // Flags for render window width and height
144*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t, render_width, 640, "Width of render window");
145*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(uint32_t, render_height, 480, "Height of render window");
146*d9f75844SAndroid Build Coastguard Worker 
147*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(
148*d9f75844SAndroid Build Coastguard Worker     std::string,
149*d9f75844SAndroid Build Coastguard Worker     force_fieldtrials,
150*d9f75844SAndroid Build Coastguard Worker     "",
151*d9f75844SAndroid Build Coastguard Worker     "Field trials control experimental feature code which can be forced. "
152*d9f75844SAndroid Build Coastguard Worker     "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enabled/"
153*d9f75844SAndroid Build Coastguard Worker     " will assign the group Enable to field trial WebRTC-FooFeature. Multiple "
154*d9f75844SAndroid Build Coastguard Worker     "trials are separated by \"/\"");
155*d9f75844SAndroid Build Coastguard Worker 
156*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(bool, simulated_time, false, "Run in simulated time");
157*d9f75844SAndroid Build Coastguard Worker 
158*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(bool, disable_preview, false, "Disable decoded video preview.");
159*d9f75844SAndroid Build Coastguard Worker 
160*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(bool, disable_decoding, false, "Disable video decoding.");
161*d9f75844SAndroid Build Coastguard Worker 
162*d9f75844SAndroid Build Coastguard Worker ABSL_FLAG(int,
163*d9f75844SAndroid Build Coastguard Worker           extend_run_time_duration,
164*d9f75844SAndroid Build Coastguard Worker           0,
165*d9f75844SAndroid Build Coastguard Worker           "Extends the run time of the receiving client after the last RTP "
166*d9f75844SAndroid Build Coastguard Worker           "packet has been delivered. Typically useful to let the last few "
167*d9f75844SAndroid Build Coastguard Worker           "frames be decoded and rendered. Duration given in seconds.");
168*d9f75844SAndroid Build Coastguard Worker 
169*d9f75844SAndroid Build Coastguard Worker namespace {
ValidatePayloadType(int32_t payload_type)170*d9f75844SAndroid Build Coastguard Worker bool ValidatePayloadType(int32_t payload_type) {
171*d9f75844SAndroid Build Coastguard Worker   return payload_type > 0 && payload_type <= 127;
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker 
ValidateOptionalPayloadType(int32_t payload_type)174*d9f75844SAndroid Build Coastguard Worker bool ValidateOptionalPayloadType(int32_t payload_type) {
175*d9f75844SAndroid Build Coastguard Worker   return payload_type == -1 || ValidatePayloadType(payload_type);
176*d9f75844SAndroid Build Coastguard Worker }
177*d9f75844SAndroid Build Coastguard Worker 
ValidateRtpHeaderExtensionId(int32_t extension_id)178*d9f75844SAndroid Build Coastguard Worker bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
179*d9f75844SAndroid Build Coastguard Worker   return extension_id >= -1 && extension_id < 15;
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker 
ValidateInputFilenameNotEmpty(const std::string & string)182*d9f75844SAndroid Build Coastguard Worker bool ValidateInputFilenameNotEmpty(const std::string& string) {
183*d9f75844SAndroid Build Coastguard Worker   return !string.empty();
184*d9f75844SAndroid Build Coastguard Worker }
185*d9f75844SAndroid Build Coastguard Worker }  // namespace
186*d9f75844SAndroid Build Coastguard Worker 
187*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
188*d9f75844SAndroid Build Coastguard Worker namespace {
189*d9f75844SAndroid Build Coastguard Worker 
190*d9f75844SAndroid Build Coastguard Worker const uint32_t kReceiverLocalSsrc = 0x123456;
191*d9f75844SAndroid Build Coastguard Worker 
192*d9f75844SAndroid Build Coastguard Worker class NullRenderer : public rtc::VideoSinkInterface<VideoFrame> {
193*d9f75844SAndroid Build Coastguard Worker  public:
OnFrame(const VideoFrame & frame)194*d9f75844SAndroid Build Coastguard Worker   void OnFrame(const VideoFrame& frame) override {}
195*d9f75844SAndroid Build Coastguard Worker };
196*d9f75844SAndroid Build Coastguard Worker 
197*d9f75844SAndroid Build Coastguard Worker class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
198*d9f75844SAndroid Build Coastguard Worker  public:
FileRenderPassthrough(const std::string & basename,rtc::VideoSinkInterface<VideoFrame> * renderer)199*d9f75844SAndroid Build Coastguard Worker   FileRenderPassthrough(const std::string& basename,
200*d9f75844SAndroid Build Coastguard Worker                         rtc::VideoSinkInterface<VideoFrame>* renderer)
201*d9f75844SAndroid Build Coastguard Worker       : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
202*d9f75844SAndroid Build Coastguard Worker 
~FileRenderPassthrough()203*d9f75844SAndroid Build Coastguard Worker   ~FileRenderPassthrough() override {
204*d9f75844SAndroid Build Coastguard Worker     if (file_)
205*d9f75844SAndroid Build Coastguard Worker       fclose(file_);
206*d9f75844SAndroid Build Coastguard Worker   }
207*d9f75844SAndroid Build Coastguard Worker 
208*d9f75844SAndroid Build Coastguard Worker  private:
OnFrame(const VideoFrame & video_frame)209*d9f75844SAndroid Build Coastguard Worker   void OnFrame(const VideoFrame& video_frame) override {
210*d9f75844SAndroid Build Coastguard Worker     if (renderer_)
211*d9f75844SAndroid Build Coastguard Worker       renderer_->OnFrame(video_frame);
212*d9f75844SAndroid Build Coastguard Worker 
213*d9f75844SAndroid Build Coastguard Worker     if (basename_.empty())
214*d9f75844SAndroid Build Coastguard Worker       return;
215*d9f75844SAndroid Build Coastguard Worker 
216*d9f75844SAndroid Build Coastguard Worker     std::stringstream filename;
217*d9f75844SAndroid Build Coastguard Worker     filename << basename_ << count_++ << "_" << video_frame.timestamp()
218*d9f75844SAndroid Build Coastguard Worker              << ".jpg";
219*d9f75844SAndroid Build Coastguard Worker 
220*d9f75844SAndroid Build Coastguard Worker     test::JpegFrameWriter frame_writer(filename.str());
221*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
222*d9f75844SAndroid Build Coastguard Worker   }
223*d9f75844SAndroid Build Coastguard Worker 
224*d9f75844SAndroid Build Coastguard Worker   const std::string basename_;
225*d9f75844SAndroid Build Coastguard Worker   rtc::VideoSinkInterface<VideoFrame>* const renderer_;
226*d9f75844SAndroid Build Coastguard Worker   FILE* file_;
227*d9f75844SAndroid Build Coastguard Worker   size_t count_;
228*d9f75844SAndroid Build Coastguard Worker };
229*d9f75844SAndroid Build Coastguard Worker 
230*d9f75844SAndroid Build Coastguard Worker class DecoderBitstreamFileWriter : public test::FakeDecoder {
231*d9f75844SAndroid Build Coastguard Worker  public:
DecoderBitstreamFileWriter(const char * filename)232*d9f75844SAndroid Build Coastguard Worker   explicit DecoderBitstreamFileWriter(const char* filename)
233*d9f75844SAndroid Build Coastguard Worker       : file_(fopen(filename, "wb")) {
234*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(file_);
235*d9f75844SAndroid Build Coastguard Worker   }
~DecoderBitstreamFileWriter()236*d9f75844SAndroid Build Coastguard Worker   ~DecoderBitstreamFileWriter() override { fclose(file_); }
237*d9f75844SAndroid Build Coastguard Worker 
Decode(const EncodedImage & encoded_frame,bool,int64_t)238*d9f75844SAndroid Build Coastguard Worker   int32_t Decode(const EncodedImage& encoded_frame,
239*d9f75844SAndroid Build Coastguard Worker                  bool /* missing_frames */,
240*d9f75844SAndroid Build Coastguard Worker                  int64_t /* render_time_ms */) override {
241*d9f75844SAndroid Build Coastguard Worker     if (fwrite(encoded_frame.data(), 1, encoded_frame.size(), file_) <
242*d9f75844SAndroid Build Coastguard Worker         encoded_frame.size()) {
243*d9f75844SAndroid Build Coastguard Worker       RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
244*d9f75844SAndroid Build Coastguard Worker       return WEBRTC_VIDEO_CODEC_ERROR;
245*d9f75844SAndroid Build Coastguard Worker     }
246*d9f75844SAndroid Build Coastguard Worker     return WEBRTC_VIDEO_CODEC_OK;
247*d9f75844SAndroid Build Coastguard Worker   }
248*d9f75844SAndroid Build Coastguard Worker 
249*d9f75844SAndroid Build Coastguard Worker  private:
250*d9f75844SAndroid Build Coastguard Worker   FILE* file_;
251*d9f75844SAndroid Build Coastguard Worker };
252*d9f75844SAndroid Build Coastguard Worker 
253*d9f75844SAndroid Build Coastguard Worker class DecoderIvfFileWriter : public test::FakeDecoder {
254*d9f75844SAndroid Build Coastguard Worker  public:
DecoderIvfFileWriter(const char * filename,const std::string & codec)255*d9f75844SAndroid Build Coastguard Worker   explicit DecoderIvfFileWriter(const char* filename, const std::string& codec)
256*d9f75844SAndroid Build Coastguard Worker       : file_writer_(
257*d9f75844SAndroid Build Coastguard Worker             IvfFileWriter::Wrap(FileWrapper::OpenWriteOnly(filename), 0)) {
258*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(file_writer_.get());
259*d9f75844SAndroid Build Coastguard Worker     if (codec == "VP8") {
260*d9f75844SAndroid Build Coastguard Worker       video_codec_type_ = VideoCodecType::kVideoCodecVP8;
261*d9f75844SAndroid Build Coastguard Worker     } else if (codec == "VP9") {
262*d9f75844SAndroid Build Coastguard Worker       video_codec_type_ = VideoCodecType::kVideoCodecVP9;
263*d9f75844SAndroid Build Coastguard Worker     } else if (codec == "H264") {
264*d9f75844SAndroid Build Coastguard Worker       video_codec_type_ = VideoCodecType::kVideoCodecH264;
265*d9f75844SAndroid Build Coastguard Worker     } else if (codec == "AV1") {
266*d9f75844SAndroid Build Coastguard Worker       video_codec_type_ = VideoCodecType::kVideoCodecAV1;
267*d9f75844SAndroid Build Coastguard Worker     } else {
268*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec;
269*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_NOTREACHED();
270*d9f75844SAndroid Build Coastguard Worker     }
271*d9f75844SAndroid Build Coastguard Worker   }
~DecoderIvfFileWriter()272*d9f75844SAndroid Build Coastguard Worker   ~DecoderIvfFileWriter() override { file_writer_->Close(); }
273*d9f75844SAndroid Build Coastguard Worker 
Decode(const EncodedImage & encoded_frame,bool,int64_t render_time_ms)274*d9f75844SAndroid Build Coastguard Worker   int32_t Decode(const EncodedImage& encoded_frame,
275*d9f75844SAndroid Build Coastguard Worker                  bool /* missing_frames */,
276*d9f75844SAndroid Build Coastguard Worker                  int64_t render_time_ms) override {
277*d9f75844SAndroid Build Coastguard Worker     if (!file_writer_->WriteFrame(encoded_frame, video_codec_type_)) {
278*d9f75844SAndroid Build Coastguard Worker       return WEBRTC_VIDEO_CODEC_ERROR;
279*d9f75844SAndroid Build Coastguard Worker     }
280*d9f75844SAndroid Build Coastguard Worker     return WEBRTC_VIDEO_CODEC_OK;
281*d9f75844SAndroid Build Coastguard Worker   }
282*d9f75844SAndroid Build Coastguard Worker 
283*d9f75844SAndroid Build Coastguard Worker  private:
284*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<IvfFileWriter> file_writer_;
285*d9f75844SAndroid Build Coastguard Worker   VideoCodecType video_codec_type_;
286*d9f75844SAndroid Build Coastguard Worker };
287*d9f75844SAndroid Build Coastguard Worker 
288*d9f75844SAndroid Build Coastguard Worker // Holds all the shared memory structures required for a receive stream. This
289*d9f75844SAndroid Build Coastguard Worker // structure is used to prevent members being deallocated before the replay
290*d9f75844SAndroid Build Coastguard Worker // has been finished.
291*d9f75844SAndroid Build Coastguard Worker struct StreamState {
292*d9f75844SAndroid Build Coastguard Worker   test::NullTransport transport;
293*d9f75844SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
294*d9f75844SAndroid Build Coastguard Worker   std::vector<VideoReceiveStreamInterface*> receive_streams;
295*d9f75844SAndroid Build Coastguard Worker   std::vector<FlexfecReceiveStream*> flexfec_streams;
296*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<VideoDecoderFactory> decoder_factory;
297*d9f75844SAndroid Build Coastguard Worker };
298*d9f75844SAndroid Build Coastguard Worker 
299*d9f75844SAndroid Build Coastguard Worker // Loads multiple configurations from the provided configuration file.
ConfigureFromFile(const std::string & config_path,Call * call)300*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StreamState> ConfigureFromFile(const std::string& config_path,
301*d9f75844SAndroid Build Coastguard Worker                                                Call* call) {
302*d9f75844SAndroid Build Coastguard Worker   auto stream_state = std::make_unique<StreamState>();
303*d9f75844SAndroid Build Coastguard Worker   // Parse the configuration file.
304*d9f75844SAndroid Build Coastguard Worker   std::ifstream config_file(config_path);
305*d9f75844SAndroid Build Coastguard Worker   std::stringstream raw_json_buffer;
306*d9f75844SAndroid Build Coastguard Worker   raw_json_buffer << config_file.rdbuf();
307*d9f75844SAndroid Build Coastguard Worker   std::string raw_json = raw_json_buffer.str();
308*d9f75844SAndroid Build Coastguard Worker   Json::CharReaderBuilder builder;
309*d9f75844SAndroid Build Coastguard Worker   Json::Value json_configs;
310*d9f75844SAndroid Build Coastguard Worker   std::string error_message;
311*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
312*d9f75844SAndroid Build Coastguard Worker   if (!json_reader->parse(raw_json.data(), raw_json.data() + raw_json.size(),
313*d9f75844SAndroid Build Coastguard Worker                           &json_configs, &error_message)) {
314*d9f75844SAndroid Build Coastguard Worker     fprintf(stderr, "Error parsing JSON config\n");
315*d9f75844SAndroid Build Coastguard Worker     fprintf(stderr, "%s\n", error_message.c_str());
316*d9f75844SAndroid Build Coastguard Worker     return nullptr;
317*d9f75844SAndroid Build Coastguard Worker   }
318*d9f75844SAndroid Build Coastguard Worker 
319*d9f75844SAndroid Build Coastguard Worker   if (absl::GetFlag(FLAGS_disable_decoding)) {
320*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory =
321*d9f75844SAndroid Build Coastguard Worker         std::make_unique<test::FunctionVideoDecoderFactory>(
322*d9f75844SAndroid Build Coastguard Worker             []() { return std::make_unique<test::FakeDecoder>(); });
323*d9f75844SAndroid Build Coastguard Worker   } else {
324*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
325*d9f75844SAndroid Build Coastguard Worker   }
326*d9f75844SAndroid Build Coastguard Worker   size_t config_count = 0;
327*d9f75844SAndroid Build Coastguard Worker   for (const auto& json : json_configs) {
328*d9f75844SAndroid Build Coastguard Worker     // Create the configuration and parse the JSON into the config.
329*d9f75844SAndroid Build Coastguard Worker     auto receive_config =
330*d9f75844SAndroid Build Coastguard Worker         ParseVideoReceiveStreamJsonConfig(&(stream_state->transport), json);
331*d9f75844SAndroid Build Coastguard Worker     // Instantiate the underlying decoder.
332*d9f75844SAndroid Build Coastguard Worker     for (auto& decoder : receive_config.decoders) {
333*d9f75844SAndroid Build Coastguard Worker       decoder = test::CreateMatchingDecoder(decoder.payload_type,
334*d9f75844SAndroid Build Coastguard Worker                                             decoder.video_format.name);
335*d9f75844SAndroid Build Coastguard Worker     }
336*d9f75844SAndroid Build Coastguard Worker     // Create a window for this config.
337*d9f75844SAndroid Build Coastguard Worker     std::stringstream window_title;
338*d9f75844SAndroid Build Coastguard Worker     window_title << "Playback Video (" << config_count++ << ")";
339*d9f75844SAndroid Build Coastguard Worker     if (absl::GetFlag(FLAGS_disable_preview)) {
340*d9f75844SAndroid Build Coastguard Worker       stream_state->sinks.emplace_back(std::make_unique<NullRenderer>());
341*d9f75844SAndroid Build Coastguard Worker     } else {
342*d9f75844SAndroid Build Coastguard Worker       stream_state->sinks.emplace_back(test::VideoRenderer::Create(
343*d9f75844SAndroid Build Coastguard Worker           window_title.str().c_str(), absl::GetFlag(FLAGS_render_width),
344*d9f75844SAndroid Build Coastguard Worker           absl::GetFlag(FLAGS_render_height)));
345*d9f75844SAndroid Build Coastguard Worker     }
346*d9f75844SAndroid Build Coastguard Worker     // Create a receive stream for this config.
347*d9f75844SAndroid Build Coastguard Worker     receive_config.renderer = stream_state->sinks.back().get();
348*d9f75844SAndroid Build Coastguard Worker     receive_config.decoder_factory = stream_state->decoder_factory.get();
349*d9f75844SAndroid Build Coastguard Worker     stream_state->receive_streams.emplace_back(
350*d9f75844SAndroid Build Coastguard Worker         call->CreateVideoReceiveStream(std::move(receive_config)));
351*d9f75844SAndroid Build Coastguard Worker   }
352*d9f75844SAndroid Build Coastguard Worker   return stream_state;
353*d9f75844SAndroid Build Coastguard Worker }
354*d9f75844SAndroid Build Coastguard Worker 
355*d9f75844SAndroid Build Coastguard Worker // Loads the base configuration from flags passed in on the commandline.
ConfigureFromFlags(const std::string & rtp_dump_path,Call * call)356*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<StreamState> ConfigureFromFlags(
357*d9f75844SAndroid Build Coastguard Worker     const std::string& rtp_dump_path,
358*d9f75844SAndroid Build Coastguard Worker     Call* call) {
359*d9f75844SAndroid Build Coastguard Worker   auto stream_state = std::make_unique<StreamState>();
360*d9f75844SAndroid Build Coastguard Worker   // Create the video renderers. We must add both to the stream state to keep
361*d9f75844SAndroid Build Coastguard Worker   // them from deallocating.
362*d9f75844SAndroid Build Coastguard Worker   std::stringstream window_title;
363*d9f75844SAndroid Build Coastguard Worker   window_title << "Playback Video (" << rtp_dump_path << ")";
364*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> playback_video;
365*d9f75844SAndroid Build Coastguard Worker   if (absl::GetFlag(FLAGS_disable_preview)) {
366*d9f75844SAndroid Build Coastguard Worker     playback_video = std::make_unique<NullRenderer>();
367*d9f75844SAndroid Build Coastguard Worker   } else {
368*d9f75844SAndroid Build Coastguard Worker     playback_video.reset(test::VideoRenderer::Create(
369*d9f75844SAndroid Build Coastguard Worker         window_title.str().c_str(), absl::GetFlag(FLAGS_render_width),
370*d9f75844SAndroid Build Coastguard Worker         absl::GetFlag(FLAGS_render_height)));
371*d9f75844SAndroid Build Coastguard Worker   }
372*d9f75844SAndroid Build Coastguard Worker   auto file_passthrough = std::make_unique<FileRenderPassthrough>(
373*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_out_base), playback_video.get());
374*d9f75844SAndroid Build Coastguard Worker   stream_state->sinks.push_back(std::move(playback_video));
375*d9f75844SAndroid Build Coastguard Worker   stream_state->sinks.push_back(std::move(file_passthrough));
376*d9f75844SAndroid Build Coastguard Worker   // Setup the configuration from the flags.
377*d9f75844SAndroid Build Coastguard Worker   VideoReceiveStreamInterface::Config receive_config(
378*d9f75844SAndroid Build Coastguard Worker       &(stream_state->transport));
379*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.remote_ssrc = absl::GetFlag(FLAGS_ssrc);
380*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
381*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.rtx_ssrc = absl::GetFlag(FLAGS_ssrc_rtx);
382*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.rtx_associated_payload_types[absl::GetFlag(
383*d9f75844SAndroid Build Coastguard Worker       FLAGS_media_payload_type_rtx)] = absl::GetFlag(FLAGS_media_payload_type);
384*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp
385*d9f75844SAndroid Build Coastguard Worker       .rtx_associated_payload_types[absl::GetFlag(FLAGS_red_payload_type_rtx)] =
386*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_red_payload_type);
387*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.ulpfec_payload_type =
388*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_ulpfec_payload_type);
389*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.red_payload_type = absl::GetFlag(FLAGS_red_payload_type);
390*d9f75844SAndroid Build Coastguard Worker   receive_config.rtp.nack.rtp_history_ms = 1000;
391*d9f75844SAndroid Build Coastguard Worker 
392*d9f75844SAndroid Build Coastguard Worker   if (absl::GetFlag(FLAGS_flexfec_payload_type) != -1) {
393*d9f75844SAndroid Build Coastguard Worker     receive_config.rtp.protected_by_flexfec = true;
394*d9f75844SAndroid Build Coastguard Worker     FlexfecReceiveStream::Config flexfec_config(&(stream_state->transport));
395*d9f75844SAndroid Build Coastguard Worker     flexfec_config.payload_type = absl::GetFlag(FLAGS_flexfec_payload_type);
396*d9f75844SAndroid Build Coastguard Worker     flexfec_config.protected_media_ssrcs.push_back(absl::GetFlag(FLAGS_ssrc));
397*d9f75844SAndroid Build Coastguard Worker     flexfec_config.rtp.remote_ssrc = absl::GetFlag(FLAGS_ssrc_flexfec);
398*d9f75844SAndroid Build Coastguard Worker     FlexfecReceiveStream* flexfec_stream =
399*d9f75844SAndroid Build Coastguard Worker         call->CreateFlexfecReceiveStream(flexfec_config);
400*d9f75844SAndroid Build Coastguard Worker     receive_config.rtp.packet_sink_ = flexfec_stream;
401*d9f75844SAndroid Build Coastguard Worker     stream_state->flexfec_streams.push_back(flexfec_stream);
402*d9f75844SAndroid Build Coastguard Worker   }
403*d9f75844SAndroid Build Coastguard Worker 
404*d9f75844SAndroid Build Coastguard Worker   if (absl::GetFlag(FLAGS_transmission_offset_id) != -1) {
405*d9f75844SAndroid Build Coastguard Worker     receive_config.rtp.extensions.push_back(
406*d9f75844SAndroid Build Coastguard Worker         RtpExtension(RtpExtension::kTimestampOffsetUri,
407*d9f75844SAndroid Build Coastguard Worker                      absl::GetFlag(FLAGS_transmission_offset_id)));
408*d9f75844SAndroid Build Coastguard Worker   }
409*d9f75844SAndroid Build Coastguard Worker   if (absl::GetFlag(FLAGS_abs_send_time_id) != -1) {
410*d9f75844SAndroid Build Coastguard Worker     receive_config.rtp.extensions.push_back(RtpExtension(
411*d9f75844SAndroid Build Coastguard Worker         RtpExtension::kAbsSendTimeUri, absl::GetFlag(FLAGS_abs_send_time_id)));
412*d9f75844SAndroid Build Coastguard Worker   }
413*d9f75844SAndroid Build Coastguard Worker   receive_config.renderer = stream_state->sinks.back().get();
414*d9f75844SAndroid Build Coastguard Worker 
415*d9f75844SAndroid Build Coastguard Worker   // Setup the receiving stream
416*d9f75844SAndroid Build Coastguard Worker   VideoReceiveStreamInterface::Decoder decoder;
417*d9f75844SAndroid Build Coastguard Worker   decoder = test::CreateMatchingDecoder(absl::GetFlag(FLAGS_media_payload_type),
418*d9f75844SAndroid Build Coastguard Worker                                         absl::GetFlag(FLAGS_codec));
419*d9f75844SAndroid Build Coastguard Worker   if (!absl::GetFlag(FLAGS_decoder_bitstream_filename).empty()) {
420*d9f75844SAndroid Build Coastguard Worker     // Replace decoder with file writer if we're writing the bitstream to a
421*d9f75844SAndroid Build Coastguard Worker     // file instead.
422*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory =
423*d9f75844SAndroid Build Coastguard Worker         std::make_unique<test::FunctionVideoDecoderFactory>([]() {
424*d9f75844SAndroid Build Coastguard Worker           return std::make_unique<DecoderBitstreamFileWriter>(
425*d9f75844SAndroid Build Coastguard Worker               absl::GetFlag(FLAGS_decoder_bitstream_filename).c_str());
426*d9f75844SAndroid Build Coastguard Worker         });
427*d9f75844SAndroid Build Coastguard Worker   } else if (!absl::GetFlag(FLAGS_decoder_ivf_filename).empty()) {
428*d9f75844SAndroid Build Coastguard Worker     // Replace decoder with file writer if we're writing the ivf to a
429*d9f75844SAndroid Build Coastguard Worker     // file instead.
430*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory =
431*d9f75844SAndroid Build Coastguard Worker         std::make_unique<test::FunctionVideoDecoderFactory>([]() {
432*d9f75844SAndroid Build Coastguard Worker           return std::make_unique<DecoderIvfFileWriter>(
433*d9f75844SAndroid Build Coastguard Worker               absl::GetFlag(FLAGS_decoder_ivf_filename).c_str(),
434*d9f75844SAndroid Build Coastguard Worker               absl::GetFlag(FLAGS_codec));
435*d9f75844SAndroid Build Coastguard Worker         });
436*d9f75844SAndroid Build Coastguard Worker   } else if (absl::GetFlag(FLAGS_disable_decoding)) {
437*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory =
438*d9f75844SAndroid Build Coastguard Worker         std::make_unique<test::FunctionVideoDecoderFactory>(
439*d9f75844SAndroid Build Coastguard Worker             []() { return std::make_unique<test::FakeDecoder>(); });
440*d9f75844SAndroid Build Coastguard Worker   } else {
441*d9f75844SAndroid Build Coastguard Worker     stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
442*d9f75844SAndroid Build Coastguard Worker   }
443*d9f75844SAndroid Build Coastguard Worker   receive_config.decoder_factory = stream_state->decoder_factory.get();
444*d9f75844SAndroid Build Coastguard Worker   receive_config.decoders.push_back(decoder);
445*d9f75844SAndroid Build Coastguard Worker 
446*d9f75844SAndroid Build Coastguard Worker   stream_state->receive_streams.emplace_back(
447*d9f75844SAndroid Build Coastguard Worker       call->CreateVideoReceiveStream(std::move(receive_config)));
448*d9f75844SAndroid Build Coastguard Worker   return stream_state;
449*d9f75844SAndroid Build Coastguard Worker }
450*d9f75844SAndroid Build Coastguard Worker 
CreateRtpReader(const std::string & rtp_dump_path)451*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<test::RtpFileReader> CreateRtpReader(
452*d9f75844SAndroid Build Coastguard Worker     const std::string& rtp_dump_path) {
453*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
454*d9f75844SAndroid Build Coastguard Worker       test::RtpFileReader::kRtpDump, rtp_dump_path));
455*d9f75844SAndroid Build Coastguard Worker   if (!rtp_reader) {
456*d9f75844SAndroid Build Coastguard Worker     rtp_reader.reset(
457*d9f75844SAndroid Build Coastguard Worker         test::RtpFileReader::Create(test::RtpFileReader::kPcap, rtp_dump_path));
458*d9f75844SAndroid Build Coastguard Worker     if (!rtp_reader) {
459*d9f75844SAndroid Build Coastguard Worker       fprintf(stderr,
460*d9f75844SAndroid Build Coastguard Worker               "Couldn't open input file as either a rtpdump or .pcap. Note "
461*d9f75844SAndroid Build Coastguard Worker               "that .pcapng is not supported.\nTrying to interpret the file as "
462*d9f75844SAndroid Build Coastguard Worker               "length/packet interleaved.\n");
463*d9f75844SAndroid Build Coastguard Worker       rtp_reader.reset(test::RtpFileReader::Create(
464*d9f75844SAndroid Build Coastguard Worker           test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
465*d9f75844SAndroid Build Coastguard Worker       if (!rtp_reader) {
466*d9f75844SAndroid Build Coastguard Worker         fprintf(stderr,
467*d9f75844SAndroid Build Coastguard Worker                 "Unable to open input file with any supported format\n");
468*d9f75844SAndroid Build Coastguard Worker         return nullptr;
469*d9f75844SAndroid Build Coastguard Worker       }
470*d9f75844SAndroid Build Coastguard Worker     }
471*d9f75844SAndroid Build Coastguard Worker   }
472*d9f75844SAndroid Build Coastguard Worker   return rtp_reader;
473*d9f75844SAndroid Build Coastguard Worker }
474*d9f75844SAndroid Build Coastguard Worker 
475*d9f75844SAndroid Build Coastguard Worker // The RtpReplayer is responsible for parsing the configuration provided by
476*d9f75844SAndroid Build Coastguard Worker // the user, setting up the windows, receive streams and decoders and then
477*d9f75844SAndroid Build Coastguard Worker // replaying the provided RTP dump.
478*d9f75844SAndroid Build Coastguard Worker class RtpReplayer final {
479*d9f75844SAndroid Build Coastguard Worker  public:
RtpReplayer(absl::string_view replay_config_path,absl::string_view rtp_dump_path,std::unique_ptr<FieldTrialsView> field_trials,bool simulated_time)480*d9f75844SAndroid Build Coastguard Worker   RtpReplayer(absl::string_view replay_config_path,
481*d9f75844SAndroid Build Coastguard Worker               absl::string_view rtp_dump_path,
482*d9f75844SAndroid Build Coastguard Worker               std::unique_ptr<FieldTrialsView> field_trials,
483*d9f75844SAndroid Build Coastguard Worker               bool simulated_time)
484*d9f75844SAndroid Build Coastguard Worker       : replay_config_path_(replay_config_path),
485*d9f75844SAndroid Build Coastguard Worker         rtp_dump_path_(rtp_dump_path),
486*d9f75844SAndroid Build Coastguard Worker         field_trials_(std::move(field_trials)),
487*d9f75844SAndroid Build Coastguard Worker         rtp_reader_(CreateRtpReader(rtp_dump_path_)) {
488*d9f75844SAndroid Build Coastguard Worker     TaskQueueFactory* task_queue_factory;
489*d9f75844SAndroid Build Coastguard Worker     if (simulated_time) {
490*d9f75844SAndroid Build Coastguard Worker       time_sim_ = std::make_unique<GlobalSimulatedTimeController>(
491*d9f75844SAndroid Build Coastguard Worker           Timestamp::Millis(1 << 30));
492*d9f75844SAndroid Build Coastguard Worker       task_queue_factory = time_sim_->GetTaskQueueFactory();
493*d9f75844SAndroid Build Coastguard Worker     } else {
494*d9f75844SAndroid Build Coastguard Worker       task_queue_factory_ = CreateDefaultTaskQueueFactory(field_trials_.get()),
495*d9f75844SAndroid Build Coastguard Worker       task_queue_factory = task_queue_factory_.get();
496*d9f75844SAndroid Build Coastguard Worker     }
497*d9f75844SAndroid Build Coastguard Worker     worker_thread_ =
498*d9f75844SAndroid Build Coastguard Worker         std::make_unique<rtc::TaskQueue>(task_queue_factory->CreateTaskQueue(
499*d9f75844SAndroid Build Coastguard Worker             "worker_thread", TaskQueueFactory::Priority::NORMAL));
500*d9f75844SAndroid Build Coastguard Worker     rtc::Event event;
501*d9f75844SAndroid Build Coastguard Worker     worker_thread_->PostTask([&]() {
502*d9f75844SAndroid Build Coastguard Worker       Call::Config call_config(&event_log_);
503*d9f75844SAndroid Build Coastguard Worker       call_config.trials = field_trials_.get();
504*d9f75844SAndroid Build Coastguard Worker       call_config.task_queue_factory = task_queue_factory;
505*d9f75844SAndroid Build Coastguard Worker       call_.reset(Call::Create(call_config));
506*d9f75844SAndroid Build Coastguard Worker 
507*d9f75844SAndroid Build Coastguard Worker       // Creation of the streams must happen inside a task queue because it is
508*d9f75844SAndroid Build Coastguard Worker       // resued as a worker thread.
509*d9f75844SAndroid Build Coastguard Worker       if (replay_config_path_.empty()) {
510*d9f75844SAndroid Build Coastguard Worker         stream_state_ = ConfigureFromFlags(rtp_dump_path_, call_.get());
511*d9f75844SAndroid Build Coastguard Worker       } else {
512*d9f75844SAndroid Build Coastguard Worker         stream_state_ = ConfigureFromFile(replay_config_path_, call_.get());
513*d9f75844SAndroid Build Coastguard Worker       }
514*d9f75844SAndroid Build Coastguard Worker       event.Set();
515*d9f75844SAndroid Build Coastguard Worker     });
516*d9f75844SAndroid Build Coastguard Worker     event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
517*d9f75844SAndroid Build Coastguard Worker 
518*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(stream_state_);
519*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(rtp_reader_);
520*d9f75844SAndroid Build Coastguard Worker   }
521*d9f75844SAndroid Build Coastguard Worker 
~RtpReplayer()522*d9f75844SAndroid Build Coastguard Worker   ~RtpReplayer() {
523*d9f75844SAndroid Build Coastguard Worker     // Destruction of streams and the call must happen on the same thread as
524*d9f75844SAndroid Build Coastguard Worker     // their creation.
525*d9f75844SAndroid Build Coastguard Worker     rtc::Event event;
526*d9f75844SAndroid Build Coastguard Worker     worker_thread_->PostTask([&]() {
527*d9f75844SAndroid Build Coastguard Worker       for (const auto& receive_stream : stream_state_->receive_streams) {
528*d9f75844SAndroid Build Coastguard Worker         call_->DestroyVideoReceiveStream(receive_stream);
529*d9f75844SAndroid Build Coastguard Worker       }
530*d9f75844SAndroid Build Coastguard Worker       for (const auto& flexfec_stream : stream_state_->flexfec_streams) {
531*d9f75844SAndroid Build Coastguard Worker         call_->DestroyFlexfecReceiveStream(flexfec_stream);
532*d9f75844SAndroid Build Coastguard Worker       }
533*d9f75844SAndroid Build Coastguard Worker       call_.reset();
534*d9f75844SAndroid Build Coastguard Worker       event.Set();
535*d9f75844SAndroid Build Coastguard Worker     });
536*d9f75844SAndroid Build Coastguard Worker     event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
537*d9f75844SAndroid Build Coastguard Worker   }
538*d9f75844SAndroid Build Coastguard Worker 
Run()539*d9f75844SAndroid Build Coastguard Worker   void Run() {
540*d9f75844SAndroid Build Coastguard Worker     rtc::Event event;
541*d9f75844SAndroid Build Coastguard Worker     worker_thread_->PostTask([&]() {
542*d9f75844SAndroid Build Coastguard Worker       // Start replaying the provided stream now that it has been configured.
543*d9f75844SAndroid Build Coastguard Worker       // VideoReceiveStreams must be started on the same thread as they were
544*d9f75844SAndroid Build Coastguard Worker       // created on.
545*d9f75844SAndroid Build Coastguard Worker       for (const auto& receive_stream : stream_state_->receive_streams) {
546*d9f75844SAndroid Build Coastguard Worker         receive_stream->Start();
547*d9f75844SAndroid Build Coastguard Worker       }
548*d9f75844SAndroid Build Coastguard Worker       event.Set();
549*d9f75844SAndroid Build Coastguard Worker     });
550*d9f75844SAndroid Build Coastguard Worker     event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
551*d9f75844SAndroid Build Coastguard Worker 
552*d9f75844SAndroid Build Coastguard Worker     ReplayPackets();
553*d9f75844SAndroid Build Coastguard Worker   }
554*d9f75844SAndroid Build Coastguard Worker 
555*d9f75844SAndroid Build Coastguard Worker  private:
ReplayPackets()556*d9f75844SAndroid Build Coastguard Worker   void ReplayPackets() {
557*d9f75844SAndroid Build Coastguard Worker     int64_t replay_start_ms = -1;
558*d9f75844SAndroid Build Coastguard Worker     int num_packets = 0;
559*d9f75844SAndroid Build Coastguard Worker     std::map<uint32_t, int> unknown_packets;
560*d9f75844SAndroid Build Coastguard Worker     rtc::Event event(/*manual_reset=*/false, /*initially_signalled=*/false);
561*d9f75844SAndroid Build Coastguard Worker     uint32_t start_timestamp = absl::GetFlag(FLAGS_start_timestamp);
562*d9f75844SAndroid Build Coastguard Worker     uint32_t stop_timestamp = absl::GetFlag(FLAGS_stop_timestamp);
563*d9f75844SAndroid Build Coastguard Worker     while (true) {
564*d9f75844SAndroid Build Coastguard Worker       int64_t now_ms = CurrentTimeMs();
565*d9f75844SAndroid Build Coastguard Worker       if (replay_start_ms == -1) {
566*d9f75844SAndroid Build Coastguard Worker         replay_start_ms = now_ms;
567*d9f75844SAndroid Build Coastguard Worker       }
568*d9f75844SAndroid Build Coastguard Worker 
569*d9f75844SAndroid Build Coastguard Worker       test::RtpPacket packet;
570*d9f75844SAndroid Build Coastguard Worker       if (!rtp_reader_->NextPacket(&packet)) {
571*d9f75844SAndroid Build Coastguard Worker         break;
572*d9f75844SAndroid Build Coastguard Worker       }
573*d9f75844SAndroid Build Coastguard Worker       rtc::CopyOnWriteBuffer packet_buffer(packet.data, packet.length);
574*d9f75844SAndroid Build Coastguard Worker       RtpPacket header;
575*d9f75844SAndroid Build Coastguard Worker       header.Parse(packet_buffer);
576*d9f75844SAndroid Build Coastguard Worker       if (header.Timestamp() < start_timestamp ||
577*d9f75844SAndroid Build Coastguard Worker           header.Timestamp() > stop_timestamp) {
578*d9f75844SAndroid Build Coastguard Worker         continue;
579*d9f75844SAndroid Build Coastguard Worker       }
580*d9f75844SAndroid Build Coastguard Worker 
581*d9f75844SAndroid Build Coastguard Worker       int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
582*d9f75844SAndroid Build Coastguard Worker       SleepOrAdvanceTime(deliver_in_ms);
583*d9f75844SAndroid Build Coastguard Worker 
584*d9f75844SAndroid Build Coastguard Worker       ++num_packets;
585*d9f75844SAndroid Build Coastguard Worker       PacketReceiver::DeliveryStatus result = PacketReceiver::DELIVERY_OK;
586*d9f75844SAndroid Build Coastguard Worker       worker_thread_->PostTask([&]() {
587*d9f75844SAndroid Build Coastguard Worker         MediaType media_type =
588*d9f75844SAndroid Build Coastguard Worker             IsRtcpPacket(packet_buffer) ? MediaType::ANY : MediaType::VIDEO;
589*d9f75844SAndroid Build Coastguard Worker         result = call_->Receiver()->DeliverPacket(media_type,
590*d9f75844SAndroid Build Coastguard Worker                                                   std::move(packet_buffer),
591*d9f75844SAndroid Build Coastguard Worker                                                   /* packet_time_us */ -1);
592*d9f75844SAndroid Build Coastguard Worker         event.Set();
593*d9f75844SAndroid Build Coastguard Worker       });
594*d9f75844SAndroid Build Coastguard Worker       event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
595*d9f75844SAndroid Build Coastguard Worker 
596*d9f75844SAndroid Build Coastguard Worker       switch (result) {
597*d9f75844SAndroid Build Coastguard Worker         case PacketReceiver::DELIVERY_OK:
598*d9f75844SAndroid Build Coastguard Worker           break;
599*d9f75844SAndroid Build Coastguard Worker         case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
600*d9f75844SAndroid Build Coastguard Worker           if (unknown_packets[header.Ssrc()] == 0)
601*d9f75844SAndroid Build Coastguard Worker             fprintf(stderr, "Unknown SSRC: %u!\n", header.Ssrc());
602*d9f75844SAndroid Build Coastguard Worker           ++unknown_packets[header.Ssrc()];
603*d9f75844SAndroid Build Coastguard Worker           break;
604*d9f75844SAndroid Build Coastguard Worker         }
605*d9f75844SAndroid Build Coastguard Worker         case PacketReceiver::DELIVERY_PACKET_ERROR: {
606*d9f75844SAndroid Build Coastguard Worker           fprintf(stderr,
607*d9f75844SAndroid Build Coastguard Worker                   "Packet error, corrupt packets or incorrect setup?\n");
608*d9f75844SAndroid Build Coastguard Worker           fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
609*d9f75844SAndroid Build Coastguard Worker                   packet.length, header.PayloadType(), header.SequenceNumber(),
610*d9f75844SAndroid Build Coastguard Worker                   header.Timestamp(), header.Ssrc());
611*d9f75844SAndroid Build Coastguard Worker           break;
612*d9f75844SAndroid Build Coastguard Worker         }
613*d9f75844SAndroid Build Coastguard Worker       }
614*d9f75844SAndroid Build Coastguard Worker     }
615*d9f75844SAndroid Build Coastguard Worker     // Note that even when `extend_run_time_duration` is zero
616*d9f75844SAndroid Build Coastguard Worker     // `SleepOrAdvanceTime` should still be called in order to process the last
617*d9f75844SAndroid Build Coastguard Worker     // delivered packet when running in simulated time.
618*d9f75844SAndroid Build Coastguard Worker     SleepOrAdvanceTime(absl::GetFlag(FLAGS_extend_run_time_duration) * 1000);
619*d9f75844SAndroid Build Coastguard Worker 
620*d9f75844SAndroid Build Coastguard Worker     fprintf(stderr, "num_packets: %d\n", num_packets);
621*d9f75844SAndroid Build Coastguard Worker 
622*d9f75844SAndroid Build Coastguard Worker     for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
623*d9f75844SAndroid Build Coastguard Worker          it != unknown_packets.end(); ++it) {
624*d9f75844SAndroid Build Coastguard Worker       fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
625*d9f75844SAndroid Build Coastguard Worker               it->second);
626*d9f75844SAndroid Build Coastguard Worker     }
627*d9f75844SAndroid Build Coastguard Worker   }
628*d9f75844SAndroid Build Coastguard Worker 
CurrentTimeMs()629*d9f75844SAndroid Build Coastguard Worker   int64_t CurrentTimeMs() {
630*d9f75844SAndroid Build Coastguard Worker     return time_sim_ ? time_sim_->GetClock()->TimeInMilliseconds()
631*d9f75844SAndroid Build Coastguard Worker                      : rtc::TimeMillis();
632*d9f75844SAndroid Build Coastguard Worker   }
633*d9f75844SAndroid Build Coastguard Worker 
SleepOrAdvanceTime(int64_t duration_ms)634*d9f75844SAndroid Build Coastguard Worker   void SleepOrAdvanceTime(int64_t duration_ms) {
635*d9f75844SAndroid Build Coastguard Worker     if (time_sim_) {
636*d9f75844SAndroid Build Coastguard Worker       time_sim_->AdvanceTime(TimeDelta::Millis(duration_ms));
637*d9f75844SAndroid Build Coastguard Worker     } else if (duration_ms > 0) {
638*d9f75844SAndroid Build Coastguard Worker       SleepMs(duration_ms);
639*d9f75844SAndroid Build Coastguard Worker     }
640*d9f75844SAndroid Build Coastguard Worker   }
641*d9f75844SAndroid Build Coastguard Worker 
642*d9f75844SAndroid Build Coastguard Worker   const std::string replay_config_path_;
643*d9f75844SAndroid Build Coastguard Worker   const std::string rtp_dump_path_;
644*d9f75844SAndroid Build Coastguard Worker   RtcEventLogNull event_log_;
645*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<FieldTrialsView> field_trials_;
646*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<GlobalSimulatedTimeController> time_sim_;
647*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<TaskQueueFactory> task_queue_factory_;
648*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<rtc::TaskQueue> worker_thread_;
649*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<Call> call_;
650*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<test::RtpFileReader> rtp_reader_;
651*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StreamState> stream_state_;
652*d9f75844SAndroid Build Coastguard Worker };
653*d9f75844SAndroid Build Coastguard Worker 
RtpReplay()654*d9f75844SAndroid Build Coastguard Worker void RtpReplay() {
655*d9f75844SAndroid Build Coastguard Worker   RtpReplayer replayer(
656*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_config_file), absl::GetFlag(FLAGS_input_file),
657*d9f75844SAndroid Build Coastguard Worker       std::make_unique<FieldTrials>(absl::GetFlag(FLAGS_force_fieldtrials)),
658*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_simulated_time));
659*d9f75844SAndroid Build Coastguard Worker   replayer.Run();
660*d9f75844SAndroid Build Coastguard Worker }
661*d9f75844SAndroid Build Coastguard Worker 
662*d9f75844SAndroid Build Coastguard Worker }  // namespace
663*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
664*d9f75844SAndroid Build Coastguard Worker 
main(int argc,char * argv[])665*d9f75844SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
666*d9f75844SAndroid Build Coastguard Worker   ::testing::InitGoogleTest(&argc, argv);
667*d9f75844SAndroid Build Coastguard Worker   absl::ParseCommandLine(argc, argv);
668*d9f75844SAndroid Build Coastguard Worker 
669*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type)));
670*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type_rtx)));
671*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type)));
672*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(
673*d9f75844SAndroid Build Coastguard Worker       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type_rtx)));
674*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(
675*d9f75844SAndroid Build Coastguard Worker       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_ulpfec_payload_type)));
676*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(
677*d9f75844SAndroid Build Coastguard Worker       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_flexfec_payload_type)));
678*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(
679*d9f75844SAndroid Build Coastguard Worker       ValidateRtpHeaderExtensionId(absl::GetFlag(FLAGS_abs_send_time_id)));
680*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ValidateRtpHeaderExtensionId(
681*d9f75844SAndroid Build Coastguard Worker       absl::GetFlag(FLAGS_transmission_offset_id)));
682*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ValidateInputFilenameNotEmpty(absl::GetFlag(FLAGS_input_file)));
683*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(absl::GetFlag(FLAGS_extend_run_time_duration), 0);
684*d9f75844SAndroid Build Coastguard Worker 
685*d9f75844SAndroid Build Coastguard Worker   rtc::ThreadManager::Instance()->WrapCurrentThread();
686*d9f75844SAndroid Build Coastguard Worker   webrtc::test::RunTest(webrtc::RtpReplay);
687*d9f75844SAndroid Build Coastguard Worker   return 0;
688*d9f75844SAndroid Build Coastguard Worker }
689