diff options
Diffstat (limited to 'third_party/libwebrtc/test/fuzzers/utils')
-rw-r--r-- | third_party/libwebrtc/test/fuzzers/utils/BUILD.gn | 48 | ||||
-rw-r--r-- | third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.cc | 202 | ||||
-rw-r--r-- | third_party/libwebrtc/test/fuzzers/utils/rtp_replayer.h | 92 |
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_ |