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