summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/test/fuzzers/utils
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/test/fuzzers/utils')
-rw-r--r--third_party/libwebrtc/test/fuzzers/utils/BUILD.gn48
-rw-r--r--third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.cc202
-rw-r--r--third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.h92
3 files changed, 342 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/fuzzers/utils/BUILD.gn b/third_party/libwebrtc/test/fuzzers/utils/BUILD.gn
new file mode 100644
index 0000000000..dfb617857c
--- /dev/null
+++ b/third_party/libwebrtc/test/fuzzers/utils/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_library("rtp_replayer") {
+ testonly = true
+ sources = [
+ "rtp_replayer.cc",
+ "rtp_replayer.h",
+ ]
+ deps = [
+ "../../../api/rtc_event_log",
+ "../../../api/task_queue:default_task_queue_factory",
+ "../../../api/test/video:function_video_factory",
+ "../../../api/transport:field_trial_based_config",
+ "../../../api/units:timestamp",
+ "../../../api/video_codecs:video_codecs_api",
+ "../../../call",
+ "../../../call:call_interfaces",
+ "../../../common_video",
+ "../../../media:rtc_internal_video_codecs",
+ "../../../modules/rtp_rtcp:rtp_rtcp_format",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_tests_utils",
+ "../../../rtc_base:rtc_json",
+ "../../../rtc_base:timeutils",
+ "../../../system_wrappers",
+ "../../../test:call_config_utils",
+ "../../../test:encoder_settings",
+ "../../../test:fake_video_codecs",
+ "../../../test:null_transport",
+ "../../../test:rtp_test_utils",
+ "../../../test:run_loop",
+ "../../../test:run_test",
+ "../../../test:run_test_interface",
+ "../../../test:test_renderer",
+ "../../../test:test_support",
+ "../../../test:test_video_capturer",
+ "../../../test:video_test_common",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/memory:memory" ]
+}
diff --git a/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.cc b/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.cc
new file mode 100644
index 0000000000..f6d7119338
--- /dev/null
+++ b/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "test/fuzzers/utils/rtp_replayer.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "api/task_queue/default_task_queue_factory.h"
+#include "api/transport/field_trial_based_config.h"
+#include "api/units/timestamp.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/strings/json.h"
+#include "system_wrappers/include/clock.h"
+#include "test/call_config_utils.h"
+#include "test/encoder_settings.h"
+#include "test/fake_decoder.h"
+#include "test/rtp_file_reader.h"
+#include "test/run_loop.h"
+
+namespace webrtc {
+namespace test {
+
+void RtpReplayer::Replay(const std::string& replay_config_filepath,
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size) {
+ auto stream_state = std::make_unique<StreamState>();
+ std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs =
+ ReadConfigFromFile(replay_config_filepath, &(stream_state->transport));
+ return Replay(std::move(stream_state), std::move(receive_stream_configs),
+ rtp_dump_data, rtp_dump_size);
+}
+
+void RtpReplayer::Replay(
+ std::unique_ptr<StreamState> stream_state,
+ std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs,
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size) {
+ RunLoop loop;
+ rtc::ScopedBaseFakeClock fake_clock;
+
+ // Work around: webrtc calls webrtc::Random(clock.TimeInMicroseconds())
+ // everywhere and Random expects non-zero seed. Let's set the clock non-zero
+ // to make them happy.
+ fake_clock.SetTime(webrtc::Timestamp::Millis(1));
+
+ // Attempt to create an RtpReader from the input file.
+ auto rtp_reader = CreateRtpReader(rtp_dump_data, rtp_dump_size);
+ if (rtp_reader == nullptr) {
+ RTC_LOG(LS_ERROR) << "Failed to create the rtp_reader";
+ return;
+ }
+
+ RtpHeaderExtensionMap extensions(/*extmap_allow_mixed=*/true);
+ // Skip i = 0 since it maps to kRtpExtensionNone.
+ for (int i = 1; i < kRtpExtensionNumberOfExtensions; i++) {
+ RTPExtensionType extension_type = static_cast<RTPExtensionType>(i);
+ // Extensions are registered with an ID, which you signal to the
+ // peer so they know what to expect. This code only cares about
+ // parsing so the value of the ID isn't relevant.
+ extensions.RegisterByType(i, extension_type);
+ }
+
+ // Setup the video streams based on the configuration.
+ webrtc::RtcEventLogNull event_log;
+ std::unique_ptr<TaskQueueFactory> task_queue_factory =
+ CreateDefaultTaskQueueFactory();
+ CallConfig call_config(&event_log);
+ call_config.task_queue_factory = task_queue_factory.get();
+ FieldTrialBasedConfig field_trials;
+ call_config.trials = &field_trials;
+ std::unique_ptr<Call> call(Call::Create(call_config));
+ SetupVideoStreams(&receive_stream_configs, stream_state.get(), call.get());
+
+ // Start replaying the provided stream now that it has been configured.
+ for (const auto& receive_stream : stream_state->receive_streams) {
+ receive_stream->Start();
+ }
+
+ ReplayPackets(&fake_clock, call.get(), rtp_reader.get(), extensions);
+
+ for (const auto& receive_stream : stream_state->receive_streams) {
+ call->DestroyVideoReceiveStream(receive_stream);
+ }
+}
+
+std::vector<VideoReceiveStreamInterface::Config>
+RtpReplayer::ReadConfigFromFile(const std::string& replay_config,
+ Transport* transport) {
+ Json::CharReaderBuilder factory;
+ std::unique_ptr<Json::CharReader> json_reader =
+ absl::WrapUnique(factory.newCharReader());
+ Json::Value json_configs;
+ Json::String errors;
+ if (!json_reader->parse(replay_config.data(),
+ replay_config.data() + replay_config.length(),
+ &json_configs, &errors)) {
+ RTC_LOG(LS_ERROR)
+ << "Error parsing JSON replay configuration for the fuzzer: " << errors;
+ return {};
+ }
+
+ std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs;
+ receive_stream_configs.reserve(json_configs.size());
+ for (const auto& json : json_configs) {
+ receive_stream_configs.push_back(
+ ParseVideoReceiveStreamJsonConfig(transport, json));
+ }
+ return receive_stream_configs;
+}
+
+void RtpReplayer::SetupVideoStreams(
+ std::vector<VideoReceiveStreamInterface::Config>* receive_stream_configs,
+ StreamState* stream_state,
+ Call* call) {
+ stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
+ for (auto& receive_config : *receive_stream_configs) {
+ // Attach the decoder for the corresponding payload type in the config.
+ for (auto& decoder : receive_config.decoders) {
+ decoder = test::CreateMatchingDecoder(decoder.payload_type,
+ decoder.video_format.name);
+ }
+
+ // Create the window to display the rendered video.
+ stream_state->sinks.emplace_back(
+ test::VideoRenderer::Create("Fuzzing WebRTC Video Config", 640, 480));
+ // Create a receive stream for this config.
+ receive_config.renderer = stream_state->sinks.back().get();
+ receive_config.decoder_factory = stream_state->decoder_factory.get();
+ stream_state->receive_streams.emplace_back(
+ call->CreateVideoReceiveStream(std::move(receive_config)));
+ }
+}
+
+std::unique_ptr<test::RtpFileReader> RtpReplayer::CreateRtpReader(
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size) {
+ std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
+ test::RtpFileReader::kRtpDump, rtp_dump_data, rtp_dump_size, {}));
+ if (!rtp_reader) {
+ RTC_LOG(LS_ERROR) << "Unable to open input file with any supported format";
+ return nullptr;
+ }
+ return rtp_reader;
+}
+
+void RtpReplayer::ReplayPackets(
+ rtc::FakeClock* clock,
+ Call* call,
+ test::RtpFileReader* rtp_reader,
+ const RtpPacketReceived::ExtensionManager& extensions) {
+ int64_t replay_start_ms = -1;
+
+ while (true) {
+ int64_t now_ms = rtc::TimeMillis();
+ if (replay_start_ms == -1) {
+ replay_start_ms = now_ms;
+ }
+
+ test::RtpPacket packet;
+ if (!rtp_reader->NextPacket(&packet)) {
+ break;
+ }
+
+ int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
+ if (deliver_in_ms > 0) {
+ // StatsCounter::ReportMetricToAggregatedCounter is O(elapsed time).
+ // Set an upper limit to prevent waste time.
+ clock->AdvanceTime(webrtc::TimeDelta::Millis(
+ std::min(deliver_in_ms, static_cast<int64_t>(100))));
+ }
+
+ RtpPacketReceived received_packet(
+ &extensions, Timestamp::Micros(clock->TimeNanos() / 1000));
+ if (!received_packet.Parse(packet.data, packet.length)) {
+ RTC_LOG(LS_ERROR) << "Packet error, corrupt packets or incorrect setup?";
+ break;
+ }
+ // Set the clock rate - always 90K for video
+ received_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency);
+
+ call->Receiver()->DeliverRtpPacket(
+ MediaType::VIDEO, std::move(received_packet),
+ [&](const RtpPacketReceived& parsed_packet) {
+ RTC_LOG(LS_ERROR) << "Unknown SSRC: " << parsed_packet.Ssrc();
+ return false;
+ });
+ }
+}
+} // namespace test
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.h b/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.h
new file mode 100644
index 0000000000..ae94a640a5
--- /dev/null
+++ b/third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TEST_FUZZERS_UTILS_RTP_REPLAYER_H_
+#define TEST_FUZZERS_UTILS_RTP_REPLAYER_H_
+
+#include <stdio.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/test/video/function_video_decoder_factory.h"
+#include "api/video_codecs/video_decoder.h"
+#include "call/call.h"
+#include "media/engine/internal_decoder_factory.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/time_utils.h"
+#include "test/null_transport.h"
+#include "test/rtp_file_reader.h"
+#include "test/test_video_capturer.h"
+#include "test/video_renderer.h"
+
+namespace webrtc {
+namespace test {
+
+// The RtpReplayer is a utility for fuzzing the RTP/RTCP receiver stack in
+// WebRTC. It achieves this by accepting a set of Receiver configurations and
+// an RtpDump (consisting of both RTP and RTCP packets). The `rtp_dump` is
+// passed in as a buffer to allow simple mutation fuzzing directly on the dump.
+class RtpReplayer final {
+ public:
+ // Holds all the important stream information required to emulate the WebRTC
+ // rtp receival code path.
+ struct StreamState {
+ test::NullTransport transport;
+ std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
+ std::vector<VideoReceiveStreamInterface*> receive_streams;
+ std::unique_ptr<VideoDecoderFactory> decoder_factory;
+ };
+
+ // Construct an RtpReplayer from a JSON replay configuration file.
+ static void Replay(const std::string& replay_config_filepath,
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size);
+
+ // Construct an RtpReplayer from a set of
+ // VideoReceiveStreamInterface::Configs. Note the stream_state.transport must
+ // be set for each receiver stream.
+ static void Replay(
+ std::unique_ptr<StreamState> stream_state,
+ std::vector<VideoReceiveStreamInterface::Config> receive_stream_config,
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size);
+
+ private:
+ // Reads the replay configuration from Json.
+ static std::vector<VideoReceiveStreamInterface::Config> ReadConfigFromFile(
+ const std::string& replay_config,
+ Transport* transport);
+
+ // Configures the stream state based on the receiver configurations.
+ static void SetupVideoStreams(
+ std::vector<VideoReceiveStreamInterface::Config>* receive_stream_configs,
+ StreamState* stream_state,
+ Call* call);
+
+ // Creates a new RtpReader which can read the RtpDump
+ static std::unique_ptr<test::RtpFileReader> CreateRtpReader(
+ const uint8_t* rtp_dump_data,
+ size_t rtp_dump_size);
+
+ // Replays each packet to from the RtpDump.
+ static void ReplayPackets(rtc::FakeClock* clock,
+ Call* call,
+ test::RtpFileReader* rtp_reader,
+ const RtpHeaderExtensionMap& extensions);
+}; // class RtpReplayer
+
+} // namespace test
+} // namespace webrtc
+
+#endif // TEST_FUZZERS_UTILS_RTP_REPLAYER_H_