mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
Add rtp_generator utility to rtc_tools.
This CL introduces a new rtp_generator tool that can be utilized to generate .rtpdump files that can be replayed by the video_replayer. This allows automated generation of corpus material for the new WebRTC RTP fuzzers in addition to allowing anyone who is experimenting with a new RTP feature to quickly debug issues. It can be used as follows: ./rtp_generator --input_config=./rtc_tools/rtp_generator/configs/vp8.json --output_rtpdump=/tmp/vp8.rtpdump ./video_replay --config_file test/fuzzers/configs/replay_packet_fuzzer/vp8_config.json --input_file /tmp/vp8.rtpdump It works by generating squares randomly on the screen for a given duration. This initial version is very limited and doesn't support FEC, RED and other configurations. I plan to extend it to support these in future CLs. Bug: webrtc:10117 Change-Id: I31d3dbb6fad73c727145ead4e7d085113d11fc51 Reviewed-on: https://webrtc-review.googlesource.com/c/119964 Commit-Queue: Benjamin Wright <benwright@webrtc.org> Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26517}
This commit is contained in:
parent
a34d7766c5
commit
87bbb91469
9 changed files with 578 additions and 104 deletions
|
@ -137,6 +137,50 @@ rtc_executable("frame_analyzer") {
|
|||
]
|
||||
}
|
||||
|
||||
rtc_executable("rtp_generator") {
|
||||
visibility = [ "*" ]
|
||||
testonly = true
|
||||
sources = [
|
||||
"rtp_generator/main.cc",
|
||||
"rtp_generator/rtp_generator.cc",
|
||||
"rtp_generator/rtp_generator.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":command_line_parser",
|
||||
"../api:libjingle_peerconnection_api",
|
||||
"../api:transport_api",
|
||||
"../api/video:builtin_video_bitrate_allocator_factory",
|
||||
"../api/video_codecs:builtin_video_decoder_factory",
|
||||
"../api/video_codecs:builtin_video_encoder_factory",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../call",
|
||||
"../call:call_interfaces",
|
||||
"../call:fake_network",
|
||||
"../call:rtp_interfaces",
|
||||
"../call:rtp_sender",
|
||||
"../call:simulated_network",
|
||||
"../call:simulated_packet_receiver",
|
||||
"../call:video_stream_api",
|
||||
"../logging:rtc_event_log_api",
|
||||
"../logging:rtc_event_log_impl_base",
|
||||
"../media:rtc_audio_video",
|
||||
"../media:rtc_media_base",
|
||||
"../rtc_base:rtc_base",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:rtc_json",
|
||||
"../rtc_base/system:file_wrapper",
|
||||
"../test:fileutils",
|
||||
"../test:rtp_test_utils",
|
||||
"../test:video_test_common",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
]
|
||||
if (!build_with_chromium && is_clang) {
|
||||
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
|
||||
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_with_chromium && !build_with_mozilla) {
|
||||
action("frame_analyzer_host") {
|
||||
script = "//tools_webrtc/executable_host_build.py"
|
||||
|
|
|
@ -3,6 +3,7 @@ include_rules = [
|
|||
"+common_audio",
|
||||
"+common_video",
|
||||
"+logging/rtc_event_log",
|
||||
"+media",
|
||||
"+modules/audio_device",
|
||||
"+modules/audio_coding/audio_network_adaptor",
|
||||
"+modules/audio_coding/neteq/include",
|
||||
|
|
13
rtc_tools/rtp_generator/configs/vp8.json
Normal file
13
rtc_tools/rtp_generator/configs/vp8.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"video_streams": [
|
||||
{
|
||||
"duration_ms": 10000,
|
||||
"video_width": 640,
|
||||
"video_height": 480,
|
||||
"video_fps": 24,
|
||||
"rtp" : {
|
||||
"payload_name" : "VP8"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
13
rtc_tools/rtp_generator/configs/vp9.json
Normal file
13
rtc_tools/rtp_generator/configs/vp9.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"video_streams": [
|
||||
{
|
||||
"duration_ms": 10000,
|
||||
"video_width": 640,
|
||||
"video_height": 480,
|
||||
"video_fps": 24,
|
||||
"rtp" : {
|
||||
"payload_name" : "VP9"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
50
rtc_tools/rtp_generator/main.cc
Normal file
50
rtc_tools/rtp_generator/main.cc
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_tools/rtp_generator/rtp_generator.h"
|
||||
#include "rtc_tools/simple_command_line_parser.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const std::string usage =
|
||||
"Generates custom configured rtpdumps for the purpose of testing.\n"
|
||||
"Example Usage:\n"
|
||||
"./rtp_generator --input_config=sender_config.json\n"
|
||||
" --output_rtpdump=my.rtpdump\n";
|
||||
|
||||
webrtc::test::CommandLineParser cmd_parser;
|
||||
cmd_parser.Init(argc, argv);
|
||||
cmd_parser.SetUsageMessage(usage);
|
||||
cmd_parser.SetFlag("input_config", "");
|
||||
cmd_parser.SetFlag("output_rtpdump", "");
|
||||
cmd_parser.ProcessFlags();
|
||||
|
||||
const std::string config_path = cmd_parser.GetFlag("input_config");
|
||||
const std::string rtp_dump_path = cmd_parser.GetFlag("output_rtpdump");
|
||||
|
||||
if (cmd_parser.GetFlag("help") == "true" || rtp_dump_path.empty() ||
|
||||
config_path.empty()) {
|
||||
cmd_parser.PrintUsageMessage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
absl::optional<webrtc::RtpGeneratorOptions> options =
|
||||
webrtc::ParseRtpGeneratorOptionsFromFile(config_path);
|
||||
if (!options.has_value()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
webrtc::RtpGenerator rtp_generator(*options);
|
||||
rtp_generator.GenerateRtpDump(rtp_dump_path);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
317
rtc_tools/rtp_generator/rtp_generator.cc
Normal file
317
rtc_tools/rtp_generator/rtp_generator.cc
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* 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 "rtc_tools/rtp_generator/rtp_generator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "api/video_codecs/builtin_video_decoder_factory.h"
|
||||
#include "api/video_codecs/builtin_video_encoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/video_encoder_config.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "rtc_base/strings/json.h"
|
||||
#include "rtc_base/system/file_wrapper.h"
|
||||
#include "rtc_base/thread.h"
|
||||
#include "test/testsupport/file_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
// Payload types.
|
||||
constexpr int kPayloadTypeVp8 = 125;
|
||||
constexpr int kPayloadTypeVp9 = 124;
|
||||
constexpr int kPayloadTypeH264 = 123;
|
||||
constexpr int kFakeVideoSendPayloadType = 122;
|
||||
|
||||
// Defaults
|
||||
constexpr int kDefaultSsrc = 1337;
|
||||
constexpr int kMaxConfigBufferSize = 8192;
|
||||
|
||||
// Utility function to validate a correct codec type has been passed in.
|
||||
bool IsValidCodecType(const std::string& codec_name) {
|
||||
return cricket::kVp8CodecName == codec_name ||
|
||||
cricket::kVp9CodecName == codec_name ||
|
||||
cricket::kH264CodecName == codec_name;
|
||||
}
|
||||
|
||||
// Utility function to return some base payload type for a codec_name.
|
||||
int GetDefaultTypeForPayloadName(const std::string& codec_name) {
|
||||
if (cricket::kVp8CodecName == codec_name) {
|
||||
return kPayloadTypeVp8;
|
||||
}
|
||||
if (cricket::kVp9CodecName == codec_name) {
|
||||
return kPayloadTypeVp9;
|
||||
}
|
||||
if (cricket::kH264CodecName == codec_name) {
|
||||
return kPayloadTypeH264;
|
||||
}
|
||||
return kFakeVideoSendPayloadType;
|
||||
}
|
||||
|
||||
// Creates a single VideoSendStream configuration.
|
||||
absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
|
||||
ParseVideoSendStreamConfig(const Json::Value& json) {
|
||||
RtpGeneratorOptions::VideoSendStreamConfig config;
|
||||
|
||||
// Parse video source settings.
|
||||
if (!rtc::GetIntFromJsonObject(json, "duration_ms", &config.duration_ms)) {
|
||||
RTC_LOG(LS_WARNING) << "duration_ms not specified using default: "
|
||||
<< config.duration_ms;
|
||||
}
|
||||
if (!rtc::GetIntFromJsonObject(json, "video_width", &config.video_width)) {
|
||||
RTC_LOG(LS_WARNING) << "video_width not specified using default: "
|
||||
<< config.video_width;
|
||||
}
|
||||
if (!rtc::GetIntFromJsonObject(json, "video_height", &config.video_height)) {
|
||||
RTC_LOG(LS_WARNING) << "video_height not specified using default: "
|
||||
<< config.video_height;
|
||||
}
|
||||
if (!rtc::GetIntFromJsonObject(json, "video_fps", &config.video_fps)) {
|
||||
RTC_LOG(LS_WARNING) << "video_fps not specified using default: "
|
||||
<< config.video_fps;
|
||||
}
|
||||
if (!rtc::GetIntFromJsonObject(json, "num_squares", &config.num_squares)) {
|
||||
RTC_LOG(LS_WARNING) << "num_squares not specified using default: "
|
||||
<< config.num_squares;
|
||||
}
|
||||
|
||||
// Parse RTP settings for this configuration.
|
||||
config.rtp.ssrcs.push_back(kDefaultSsrc);
|
||||
Json::Value rtp_json;
|
||||
if (!rtc::GetValueFromJsonObject(json, "rtp", &rtp_json)) {
|
||||
RTC_LOG(LS_ERROR) << "video_streams must have an rtp section";
|
||||
return absl::nullopt;
|
||||
}
|
||||
if (!rtc::GetStringFromJsonObject(rtp_json, "payload_name",
|
||||
&config.rtp.payload_name)) {
|
||||
RTC_LOG(LS_ERROR) << "rtp.payload_name must be specified";
|
||||
return absl::nullopt;
|
||||
}
|
||||
if (!IsValidCodecType(config.rtp.payload_name)) {
|
||||
RTC_LOG(LS_ERROR) << "rtp.payload_name must be VP8,VP9 or H264";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
config.rtp.payload_type =
|
||||
GetDefaultTypeForPayloadName(config.rtp.payload_name);
|
||||
if (!rtc::GetIntFromJsonObject(rtp_json, "payload_type",
|
||||
&config.rtp.payload_type)) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "rtp.payload_type not specified using default for codec type"
|
||||
<< config.rtp.payload_type;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::optional<RtpGeneratorOptions> ParseRtpGeneratorOptionsFromFile(
|
||||
const std::string& options_file) {
|
||||
if (!test::FileExists(options_file)) {
|
||||
RTC_LOG(LS_ERROR) << " configuration file does not exist";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Read the configuration file from disk.
|
||||
FileWrapper config_file = FileWrapper::OpenReadOnly(options_file);
|
||||
std::vector<char> raw_json_buffer(kMaxConfigBufferSize, 0);
|
||||
size_t bytes_read =
|
||||
config_file.Read(raw_json_buffer.data(), raw_json_buffer.size() - 1);
|
||||
if (bytes_read == 0) {
|
||||
RTC_LOG(LS_ERROR) << "Unable to read the configuration file.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Parse the file as JSON
|
||||
Json::Reader json_reader;
|
||||
Json::Value json;
|
||||
if (!json_reader.parse(raw_json_buffer.data(), json)) {
|
||||
RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
RtpGeneratorOptions gen_options;
|
||||
for (const auto& video_stream_json : json["video_streams"]) {
|
||||
absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
|
||||
video_stream_config = ParseVideoSendStreamConfig(video_stream_json);
|
||||
if (!video_stream_config.has_value()) {
|
||||
RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file";
|
||||
return absl::nullopt;
|
||||
}
|
||||
gen_options.video_streams.push_back(*video_stream_config);
|
||||
}
|
||||
return gen_options;
|
||||
}
|
||||
|
||||
RtpGenerator::RtpGenerator(const RtpGeneratorOptions& options)
|
||||
: options_(options),
|
||||
video_encoder_factory_(CreateBuiltinVideoEncoderFactory()),
|
||||
video_decoder_factory_(CreateBuiltinVideoDecoderFactory()),
|
||||
video_bitrate_allocator_factory_(
|
||||
CreateBuiltinVideoBitrateAllocatorFactory()),
|
||||
event_log_(webrtc::RtcEventLog::CreateNull()),
|
||||
call_(Call::Create(CallConfig(event_log_.get()))) {
|
||||
constexpr int kMinBitrateBps = 30000; // 30 Kbps
|
||||
constexpr int kMaxBitrateBps = 2500000; // 2.5 Mbps
|
||||
|
||||
int stream_count = 0;
|
||||
for (const auto& send_config : options.video_streams) {
|
||||
webrtc::VideoSendStream::Config video_config(this);
|
||||
video_config.encoder_settings.encoder_factory =
|
||||
video_encoder_factory_.get();
|
||||
video_config.encoder_settings.bitrate_allocator_factory =
|
||||
video_bitrate_allocator_factory_.get();
|
||||
video_config.rtp = send_config.rtp;
|
||||
// Update some required to be unique values.
|
||||
stream_count++;
|
||||
video_config.rtp.mid = "mid-" + std::to_string(stream_count);
|
||||
video_config.track_id = "track-" + std::to_string(stream_count);
|
||||
|
||||
// Configure the video encoder configuration.
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.content_type =
|
||||
VideoEncoderConfig::ContentType::kRealtimeVideo;
|
||||
encoder_config.codec_type =
|
||||
PayloadStringToCodecType(video_config.rtp.payload_name);
|
||||
if (video_config.rtp.payload_name == cricket::kVp8CodecName) {
|
||||
VideoCodecVP8 settings = VideoEncoder::GetDefaultVp8Settings();
|
||||
encoder_config.encoder_specific_settings = new rtc::RefCountedObject<
|
||||
VideoEncoderConfig::Vp8EncoderSpecificSettings>(settings);
|
||||
} else if (video_config.rtp.payload_name == cricket::kVp9CodecName) {
|
||||
VideoCodecVP9 settings = VideoEncoder::GetDefaultVp9Settings();
|
||||
encoder_config.encoder_specific_settings = new rtc::RefCountedObject<
|
||||
VideoEncoderConfig::Vp9EncoderSpecificSettings>(settings);
|
||||
} else if (video_config.rtp.payload_name == cricket::kH264CodecName) {
|
||||
VideoCodecH264 settings = VideoEncoder::GetDefaultH264Settings();
|
||||
encoder_config.encoder_specific_settings = new rtc::RefCountedObject<
|
||||
VideoEncoderConfig::H264EncoderSpecificSettings>(settings);
|
||||
}
|
||||
encoder_config.video_format.name = video_config.rtp.payload_name;
|
||||
encoder_config.min_transmit_bitrate_bps = 0;
|
||||
encoder_config.max_bitrate_bps = kMaxBitrateBps;
|
||||
encoder_config.content_type =
|
||||
VideoEncoderConfig::ContentType::kRealtimeVideo;
|
||||
|
||||
// Configure the simulcast layers.
|
||||
encoder_config.number_of_streams = video_config.rtp.ssrcs.size();
|
||||
encoder_config.bitrate_priority = 1.0;
|
||||
encoder_config.simulcast_layers.resize(encoder_config.number_of_streams);
|
||||
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
||||
encoder_config.simulcast_layers[i].active = true;
|
||||
encoder_config.simulcast_layers[i].min_bitrate_bps = kMinBitrateBps;
|
||||
encoder_config.simulcast_layers[i].max_bitrate_bps = kMaxBitrateBps;
|
||||
encoder_config.simulcast_layers[i].max_framerate = send_config.video_fps;
|
||||
}
|
||||
|
||||
encoder_config.video_stream_factory =
|
||||
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
|
||||
video_config.rtp.payload_name, /*max qp*/ 56, /*screencast*/ false,
|
||||
/*screenshare enabled*/ false);
|
||||
|
||||
// Setup the fake video stream for this.
|
||||
std::unique_ptr<test::FrameGeneratorCapturer> frame_generator(
|
||||
test::FrameGeneratorCapturer::Create(
|
||||
send_config.video_width, send_config.video_height, absl::nullopt,
|
||||
absl::nullopt, send_config.video_fps, Clock::GetRealTimeClock()));
|
||||
frame_generator->Init();
|
||||
|
||||
VideoSendStream* video_send_stream = call_->CreateVideoSendStream(
|
||||
std::move(video_config), std::move(encoder_config));
|
||||
video_send_stream->SetSource(
|
||||
frame_generator.get(),
|
||||
webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
// Store these objects so we can destropy them at the end.
|
||||
frame_generators_.push_back(std::move(frame_generator));
|
||||
video_send_streams_.push_back(video_send_stream);
|
||||
}
|
||||
}
|
||||
|
||||
RtpGenerator::~RtpGenerator() {
|
||||
for (VideoSendStream* send_stream : video_send_streams_) {
|
||||
call_->DestroyVideoSendStream(send_stream);
|
||||
}
|
||||
}
|
||||
|
||||
void RtpGenerator::GenerateRtpDump(const std::string& rtp_dump_path) {
|
||||
rtp_dump_writer_.reset(test::RtpFileWriter::Create(
|
||||
test::RtpFileWriter::kRtpDump, rtp_dump_path));
|
||||
|
||||
call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
|
||||
webrtc::kNetworkUp);
|
||||
for (VideoSendStream* send_stream : video_send_streams_) {
|
||||
send_stream->Start();
|
||||
}
|
||||
|
||||
// Spinlock until all the durations end.
|
||||
WaitUntilAllVideoStreamsFinish();
|
||||
|
||||
call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
|
||||
webrtc::kNetworkDown);
|
||||
}
|
||||
|
||||
bool RtpGenerator::SendRtp(const uint8_t* packet,
|
||||
size_t length,
|
||||
const webrtc::PacketOptions& options) {
|
||||
test::RtpPacket rtp_packet = DataToRtpPacket(packet, length);
|
||||
rtp_dump_writer_->WritePacket(&rtp_packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RtpGenerator::SendRtcp(const uint8_t* packet, size_t length) {
|
||||
test::RtpPacket rtcp_packet = DataToRtpPacket(packet, length);
|
||||
rtp_dump_writer_->WritePacket(&rtcp_packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
int RtpGenerator::GetMaxDuration() const {
|
||||
int max_end_ms = 0;
|
||||
for (const auto& video_stream : options_.video_streams) {
|
||||
max_end_ms = std::max(video_stream.duration_ms, max_end_ms);
|
||||
}
|
||||
return max_end_ms;
|
||||
}
|
||||
|
||||
void RtpGenerator::WaitUntilAllVideoStreamsFinish() {
|
||||
// Find the maximum duration required by the streams.
|
||||
start_ms_ = Clock::GetRealTimeClock()->TimeInMilliseconds();
|
||||
int64_t max_end_ms = start_ms_ + GetMaxDuration();
|
||||
|
||||
int64_t current_time = 0;
|
||||
do {
|
||||
int64_t min_wait_time = 0;
|
||||
current_time = Clock::GetRealTimeClock()->TimeInMilliseconds();
|
||||
// Stop any streams that are no longer active.
|
||||
for (size_t i = 0; i < options_.video_streams.size(); ++i) {
|
||||
const int64_t end_ms = start_ms_ + options_.video_streams[i].duration_ms;
|
||||
if (current_time > end_ms) {
|
||||
video_send_streams_[i]->Stop();
|
||||
} else {
|
||||
min_wait_time = std::min(min_wait_time, end_ms - current_time);
|
||||
}
|
||||
}
|
||||
rtc::Thread::Current()->SleepMs(min_wait_time);
|
||||
} while (current_time < max_end_ms);
|
||||
}
|
||||
|
||||
test::RtpPacket RtpGenerator::DataToRtpPacket(const uint8_t* packet,
|
||||
size_t packet_len) {
|
||||
webrtc::test::RtpPacket rtp_packet;
|
||||
memcpy(rtp_packet.data, packet, packet_len);
|
||||
rtp_packet.length = packet_len;
|
||||
rtp_packet.original_length = packet_len;
|
||||
rtp_packet.time_ms =
|
||||
webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_;
|
||||
return rtp_packet;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
122
rtc_tools/rtp_generator/rtp_generator.h
Normal file
122
rtc_tools/rtp_generator/rtp_generator.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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 RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_
|
||||
#define RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/call/transport.h"
|
||||
#include "api/media_types.h"
|
||||
#include "api/video/builtin_video_bitrate_allocator_factory.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder_config.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
#include "call/call.h"
|
||||
#include "call/rtp_config.h"
|
||||
#include "call/video_send_stream.h"
|
||||
#include "logging/rtc_event_log/rtc_event_log.h"
|
||||
#include "media/engine/webrtc_video_engine.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "test/frame_generator.h"
|
||||
#include "test/frame_generator_capturer.h"
|
||||
#include "test/rtp_file_reader.h"
|
||||
#include "test/rtp_file_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Specifies all the configurable options to pass to the corpus generator.
|
||||
// If modified please update the JSON parser as well as all.
|
||||
struct RtpGeneratorOptions {
|
||||
struct VideoSendStreamConfig {
|
||||
// The time to record the RtpDump for.
|
||||
int duration_ms = 10000;
|
||||
// The video resolution width.
|
||||
int video_width = 640;
|
||||
// The video resolution height.
|
||||
int video_height = 480;
|
||||
// The video fps.
|
||||
int video_fps = 24;
|
||||
// The number of squares to render.
|
||||
int num_squares = 128;
|
||||
// The individual RTP configuration.
|
||||
RtpConfig rtp;
|
||||
};
|
||||
// Multiple senders can be active at once on an rtp channel.
|
||||
std::vector<VideoSendStreamConfig> video_streams;
|
||||
};
|
||||
|
||||
// Attempts to parse RtpGeneratorOptions from a JSON file. Any failures
|
||||
// will result in absl::nullopt.
|
||||
absl::optional<RtpGeneratorOptions> ParseRtpGeneratorOptionsFromFile(
|
||||
const std::string& options_file);
|
||||
|
||||
// The RtpGenerator allows generating of corpus material intended to be
|
||||
// used by fuzzers. It accepts a simple Json configuration file that allows the
|
||||
// user to configure the codec, extensions and error correction mechanisms. It
|
||||
// will then proceed to generate an rtpdump for the specified duration using
|
||||
// that configuration that can be replayed by the video_replayer. The receiver
|
||||
// configuration JSON will also be output and can be replayed as follows:
|
||||
// ./rtp_generator --config_file sender_config --output_rtpdump my.rtpdump
|
||||
// --output_config receiver_config.json
|
||||
// ./video_replay --config_file receiver_config.json --output_file my.rtpdump
|
||||
//
|
||||
// It achieves this by creating a VideoStreamSender, configuring it as requested
|
||||
// by the user and then intercepting all outgoing RTP packets and writing them
|
||||
// to a file instead of out of the network. It then uses this sender
|
||||
// configuration to generate a mirror receiver configuration that can be read by
|
||||
// the video_replay program.
|
||||
class RtpGenerator final : public webrtc::Transport {
|
||||
public:
|
||||
// Construct a new RtpGenerator using the specified options.
|
||||
explicit RtpGenerator(const RtpGeneratorOptions& options);
|
||||
// Cleans up the VideoSendStream.
|
||||
~RtpGenerator() override;
|
||||
// Generates an rtp_dump that is written out to
|
||||
void GenerateRtpDump(const std::string& rtp_dump_path);
|
||||
|
||||
private:
|
||||
// webrtc::Transport implementation
|
||||
// Captured RTP packets are written to the RTPDump file instead of over the
|
||||
// network.
|
||||
bool SendRtp(const uint8_t* packet,
|
||||
size_t length,
|
||||
const webrtc::PacketOptions& options) override;
|
||||
// RTCP packets are ignored for now.
|
||||
bool SendRtcp(const uint8_t* packet, size_t length) override;
|
||||
// Returns the maximum duration
|
||||
int GetMaxDuration() const;
|
||||
// Waits until all video streams have finished.
|
||||
void WaitUntilAllVideoStreamsFinish();
|
||||
// Converts packet data into an RtpPacket.
|
||||
test::RtpPacket DataToRtpPacket(const uint8_t* packet, size_t packet_len);
|
||||
|
||||
const RtpGeneratorOptions options_;
|
||||
std::unique_ptr<VideoEncoderFactory> video_encoder_factory_;
|
||||
std::unique_ptr<VideoDecoderFactory> video_decoder_factory_;
|
||||
std::unique_ptr<VideoBitrateAllocatorFactory>
|
||||
video_bitrate_allocator_factory_;
|
||||
std::unique_ptr<RtcEventLog> event_log_;
|
||||
std::unique_ptr<Call> call_;
|
||||
std::unique_ptr<test::RtpFileWriter> rtp_dump_writer_;
|
||||
std::vector<std::unique_ptr<test::FrameGeneratorCapturer>> frame_generators_;
|
||||
std::vector<VideoSendStream*> video_send_streams_;
|
||||
std::vector<uint32_t> durations_ms_;
|
||||
uint32_t start_ms_ = 0;
|
||||
|
||||
// This object cannot be copied.
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpGenerator);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_
|
|
@ -3,65 +3,24 @@
|
|||
{
|
||||
"codec_params" : [],
|
||||
"payload_name" : "VP8",
|
||||
"payload_type" : 96
|
||||
},
|
||||
{
|
||||
"codec_params" : [],
|
||||
"payload_name" : "VP9",
|
||||
"payload_type" : 98
|
||||
"payload_type" : 125
|
||||
}
|
||||
],
|
||||
"render_delay_ms" : 10,
|
||||
"rtp" : {
|
||||
"extensions" : [
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 5,
|
||||
"uri" : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 3,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 6,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 4,
|
||||
"uri" : "urn:3gpp:video-orientation"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 2,
|
||||
"uri" : "urn:ietf:params:rtp-hdrext:toffset"
|
||||
}
|
||||
],
|
||||
"local_ssrc" : 2129427193,
|
||||
"extensions" : [],
|
||||
"local_ssrc" : 7331,
|
||||
"nack" : {
|
||||
"rtp_history_ms" : 1000
|
||||
},
|
||||
"red_payload_type" : 100,
|
||||
"red_payload_type" : -1,
|
||||
"remb" : true,
|
||||
"remote_ssrc" : 2060300048,
|
||||
"remote_ssrc" : 1337,
|
||||
"rtcp_mode" : "RtcpMode::kCompound",
|
||||
"rtx_payload_types" : [
|
||||
{
|
||||
"97" : 96
|
||||
},
|
||||
{
|
||||
"99" : 98
|
||||
},
|
||||
{
|
||||
"101" : 100
|
||||
}
|
||||
],
|
||||
"rtx_payload_types" : [],
|
||||
"rtx_ssrc" : 100,
|
||||
"transport_cc" : true,
|
||||
"ulpfec_payload_type" : 102
|
||||
"ulpfec_payload_type" : -1
|
||||
},
|
||||
"target_delay_ms" : 0
|
||||
}]
|
||||
|
|
|
@ -1,71 +1,26 @@
|
|||
[
|
||||
{
|
||||
[{
|
||||
"decoders" : [
|
||||
{
|
||||
"codec_params" : [],
|
||||
"payload_name" : "VP9",
|
||||
"payload_type" : 96
|
||||
"payload_type" : 124
|
||||
}
|
||||
],
|
||||
"render_delay_ms" : 10,
|
||||
"rtp" : {
|
||||
"extensions" : [
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 5,
|
||||
"uri" : "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 3,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 6,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 7,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 8,
|
||||
"uri" : "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 4,
|
||||
"uri" : "urn:3gpp:video-orientation"
|
||||
},
|
||||
{
|
||||
"encrypt" : false,
|
||||
"id" : 2,
|
||||
"uri" : "urn:ietf:params:rtp-hdrext:toffset"
|
||||
}
|
||||
],
|
||||
"local_ssrc" : 1,
|
||||
"extensions" : [],
|
||||
"local_ssrc" : 7331,
|
||||
"nack" : {
|
||||
"rtp_history_ms" : 1000
|
||||
},
|
||||
"red_payload_type" : 100,
|
||||
"red_payload_type" : -1,
|
||||
"remb" : true,
|
||||
"remote_ssrc" : 359403851,
|
||||
"rtcp_mode" : "RtcpMode::kReducedSize",
|
||||
"rtx_payload_types" : [
|
||||
{
|
||||
"97" : 96
|
||||
},
|
||||
{
|
||||
"101" : 100
|
||||
}
|
||||
],
|
||||
"rtx_ssrc" : 1732909516,
|
||||
"remote_ssrc" : 1337,
|
||||
"rtcp_mode" : "RtcpMode::kCompound",
|
||||
"rtx_payload_types" : [],
|
||||
"rtx_ssrc" : 100,
|
||||
"transport_cc" : true,
|
||||
"ulpfec_payload_type" : 127
|
||||
"ulpfec_payload_type" : -1
|
||||
},
|
||||
"target_delay_ms" : 0
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
|
Loading…
Reference in a new issue