Fuzzing support for RTPDump VP8 and VP9 Streams.
This change integrates fuzzing support for RtpDumps in WebRTC. This allows LibFuzzer to directly fuzz the RTP code path from packet arrival all the way to actual decoding and rendering. It does this by replaying each RTP packet in the RTPDump which can be mutated directly by the fuzzer. For fuzzing support the RtpFileReader needs to support reading from a buffer instead of an file. The test class requires FILE* for all its parsing operations and is deeply coupled this way. I chose to solve this problem at an OS level by using the tmpfile() option and copying the buffer to the tmpfile(). fmemopen() is no available on most platforms so couldn't be used as a generic solution. The additional copy isn't ideal but won't be a bottleneck for the fuzzing. In the future I plan for the fuzzers to read from a configuration file. But given the current packaging strategy for fuzzers in WebRTC this isn't easy. Bug: webrtc:9860 Change-Id: I2560120e82663f9e9fb5b9640e6a6d16f9c1a360 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/126682 Reviewed-by: Niels Moller <nisse@webrtc.org> Commit-Queue: Benjamin Wright <benwright@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27151}
This commit is contained in:
parent
e07d3b432a
commit
47dbcabc2e
@ -628,3 +628,27 @@ webrtc_fuzzer_test("ssl_certificate_fuzzer") {
|
||||
"../../modules/rtp_rtcp",
|
||||
]
|
||||
}
|
||||
|
||||
webrtc_fuzzer_test("vp8_replay_fuzzer") {
|
||||
sources = [
|
||||
"vp8_replay_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"utils:rtp_replayer",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
]
|
||||
seed_corpus = "corpora/rtpdump-corpus/vp8"
|
||||
}
|
||||
|
||||
webrtc_fuzzer_test("vp9_replay_fuzzer") {
|
||||
sources = [
|
||||
"vp9_replay_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"utils:rtp_replayer",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
]
|
||||
seed_corpus = "corpora/rtpdump-corpus/vp9"
|
||||
}
|
||||
|
||||
BIN
test/fuzzers/corpora/rtpdump-corpus/vp8/vp8.rtpdump
Normal file
BIN
test/fuzzers/corpora/rtpdump-corpus/vp8/vp8.rtpdump
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/rtpdump-corpus/vp9/vp9.rtpdump
Normal file
BIN
test/fuzzers/corpora/rtpdump-corpus/vp9/vp9.rtpdump
Normal file
Binary file not shown.
40
test/fuzzers/utils/BUILD.gn
Normal file
40
test/fuzzers/utils/BUILD.gn
Normal file
@ -0,0 +1,40 @@
|
||||
# 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_source_set("rtp_replayer") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"rtp_replayer.cc",
|
||||
"rtp_replayer.h",
|
||||
]
|
||||
deps = [
|
||||
"../../../api/test/video:function_video_factory",
|
||||
"../../../api/video_codecs:video_codecs_api",
|
||||
"../../../call:call_interfaces",
|
||||
"../../../common_video",
|
||||
"../../../logging:rtc_event_log_api",
|
||||
"../../../media:rtc_internal_video_codecs",
|
||||
"../../../modules/rtp_rtcp",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base:rtc_json",
|
||||
"../../../system_wrappers",
|
||||
"../../../test:call_config_utils",
|
||||
"../../../test:fake_video_codecs",
|
||||
"../../../test:rtp_test_utils",
|
||||
"../../../test:run_test",
|
||||
"../../../test:run_test_interface",
|
||||
"../../../test:test_common",
|
||||
"../../../test:test_renderer",
|
||||
"../../../test:test_support",
|
||||
"../../../test:video_test_common",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
]
|
||||
}
|
||||
188
test/fuzzers/utils/rtp_replayer.cc
Normal file
188
test/fuzzers/utils/rtp_replayer.cc
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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 <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
#include "rtc_base/strings/json.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "system_wrappers/include/sleep.h"
|
||||
#include "test/call_config_utils.h"
|
||||
#include "test/encoder_settings.h"
|
||||
#include "test/fake_decoder.h"
|
||||
#include "test/rtp_file_reader.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 = absl::make_unique<StreamState>();
|
||||
std::vector<VideoReceiveStream::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<VideoReceiveStream::Config> receive_stream_configs,
|
||||
const uint8_t* rtp_dump_data,
|
||||
size_t rtp_dump_size) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Setup the video streams based on the configuration.
|
||||
webrtc::RtcEventLogNullImpl event_log;
|
||||
Call::Config call_config(&event_log);
|
||||
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(call.get(), rtp_reader.get());
|
||||
|
||||
for (const auto& receive_stream : stream_state->receive_streams) {
|
||||
call->DestroyVideoReceiveStream(receive_stream);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<VideoReceiveStream::Config> RtpReplayer::ReadConfigFromFile(
|
||||
const std::string& replay_config,
|
||||
Transport* transport) {
|
||||
Json::Reader json_reader;
|
||||
Json::Value json_configs;
|
||||
if (!json_reader.parse(replay_config, json_configs)) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "Error parsing JSON replay configuration for the fuzzer"
|
||||
<< json_reader.getFormatedErrorMessages();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<VideoReceiveStream::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<VideoReceiveStream::Config>* receive_stream_configs,
|
||||
StreamState* stream_state,
|
||||
Call* call) {
|
||||
stream_state->decoder_factory = absl::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);
|
||||
decoder.decoder_factory = stream_state->decoder_factory.get();
|
||||
}
|
||||
|
||||
// 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();
|
||||
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(Call* call, test::RtpFileReader* rtp_reader) {
|
||||
int64_t replay_start_ms = -1;
|
||||
int num_packets = 0;
|
||||
std::map<uint32_t, int> unknown_packets;
|
||||
|
||||
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) {
|
||||
SleepMs(deliver_in_ms);
|
||||
}
|
||||
|
||||
++num_packets;
|
||||
switch (call->Receiver()->DeliverPacket(
|
||||
webrtc::MediaType::VIDEO,
|
||||
rtc::CopyOnWriteBuffer(packet.data, packet.length),
|
||||
/* packet_time_us */ -1)) {
|
||||
case PacketReceiver::DELIVERY_OK:
|
||||
break;
|
||||
case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
|
||||
RTPHeader header;
|
||||
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
|
||||
|
||||
parser->Parse(packet.data, packet.length, &header);
|
||||
if (unknown_packets[header.ssrc] == 0) {
|
||||
RTC_LOG(LS_ERROR) << "Unknown SSRC: " << header.ssrc;
|
||||
}
|
||||
++unknown_packets[header.ssrc];
|
||||
break;
|
||||
}
|
||||
case PacketReceiver::DELIVERY_PACKET_ERROR: {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "Packet error, corrupt packets or incorrect setup?";
|
||||
RTPHeader header;
|
||||
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
|
||||
parser->Parse(packet.data, packet.length, &header);
|
||||
RTC_LOG(LS_ERROR) << "Packet packet_length=" << packet.length
|
||||
<< " payload_type=" << header.payloadType
|
||||
<< " sequence_number=" << header.sequenceNumber
|
||||
<< " time_stamp=" << header.timestamp
|
||||
<< " ssrc=" << header.ssrc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RTC_LOG(LS_INFO) << "num_packets: " << num_packets;
|
||||
|
||||
for (const auto& unknown_packet : unknown_packets) {
|
||||
RTC_LOG(LS_ERROR) << "Packets for unknown ssrc " << unknown_packet.first
|
||||
<< ":" << unknown_packet.second;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
87
test/fuzzers/utils/rtp_replayer.h
Normal file
87
test/fuzzers/utils/rtp_replayer.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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/test/video/function_video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
#include "call/call.h"
|
||||
#include "logging/rtc_event_log/rtc_event_log.h"
|
||||
#include "media/engine/internal_decoder_factory.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<VideoReceiveStream*> 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 VideoReceiveStream::Configs. Note
|
||||
// the stream_state.transport must be set for each receiver stream.
|
||||
static void Replay(
|
||||
std::unique_ptr<StreamState> stream_state,
|
||||
std::vector<VideoReceiveStream::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<VideoReceiveStream::Config> ReadConfigFromFile(
|
||||
const std::string& replay_config,
|
||||
Transport* transport);
|
||||
|
||||
// Configures the stream state based on the receiver configurations.
|
||||
static void SetupVideoStreams(
|
||||
std::vector<VideoReceiveStream::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(Call* call, test::RtpFileReader* rtp_reader);
|
||||
}; // class RtpReplayer
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_FUZZERS_UTILS_RTP_REPLAYER_H_
|
||||
42
test/fuzzers/vp8_replay_fuzzer.cc
Normal file
42
test/fuzzers/vp8_replay_fuzzer.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "test/fuzzers/utils/rtp_replayer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void FuzzOneInput(const uint8_t* data, size_t size) {
|
||||
auto stream_state = absl::make_unique<test::RtpReplayer::StreamState>();
|
||||
VideoReceiveStream::Config vp8_config(&(stream_state->transport));
|
||||
|
||||
VideoReceiveStream::Decoder vp8_decoder;
|
||||
vp8_decoder.video_format = SdpVideoFormat("VP8");
|
||||
vp8_decoder.payload_type = 125;
|
||||
vp8_config.decoders.push_back(std::move(vp8_decoder));
|
||||
|
||||
vp8_config.rtp.local_ssrc = 7731;
|
||||
vp8_config.rtp.remote_ssrc = 1337;
|
||||
vp8_config.rtp.rtx_ssrc = 100;
|
||||
vp8_config.rtp.transport_cc = true;
|
||||
vp8_config.rtp.remb = true;
|
||||
vp8_config.rtp.nack.rtp_history_ms = 1000;
|
||||
|
||||
std::vector<VideoReceiveStream::Config> replay_configs;
|
||||
replay_configs.push_back(std::move(vp8_config));
|
||||
|
||||
test::RtpReplayer::Replay(std::move(stream_state), std::move(replay_configs),
|
||||
data, size);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
42
test/fuzzers/vp9_replay_fuzzer.cc
Normal file
42
test/fuzzers/vp9_replay_fuzzer.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "test/fuzzers/utils/rtp_replayer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void FuzzOneInput(const uint8_t* data, size_t size) {
|
||||
auto stream_state = absl::make_unique<test::RtpReplayer::StreamState>();
|
||||
VideoReceiveStream::Config vp9_config(&(stream_state->transport));
|
||||
|
||||
VideoReceiveStream::Decoder vp9_decoder;
|
||||
vp9_decoder.video_format = SdpVideoFormat("VP9");
|
||||
vp9_decoder.payload_type = 124;
|
||||
vp9_config.decoders.push_back(std::move(vp9_decoder));
|
||||
|
||||
vp9_config.rtp.local_ssrc = 7731;
|
||||
vp9_config.rtp.remote_ssrc = 1337;
|
||||
vp9_config.rtp.rtx_ssrc = 100;
|
||||
vp9_config.rtp.transport_cc = true;
|
||||
vp9_config.rtp.remb = true;
|
||||
vp9_config.rtp.nack.rtp_history_ms = 1000;
|
||||
|
||||
std::vector<VideoReceiveStream::Config> replay_configs;
|
||||
replay_configs.push_back(std::move(vp9_config));
|
||||
|
||||
test::RtpReplayer::Replay(std::move(stream_state), std::move(replay_configs),
|
||||
data, size);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -63,30 +63,25 @@ bool ReadUint16(uint16_t* out, FILE* file) {
|
||||
|
||||
class RtpFileReaderImpl : public RtpFileReader {
|
||||
public:
|
||||
virtual bool Init(const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) = 0;
|
||||
virtual bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) = 0;
|
||||
};
|
||||
|
||||
class InterleavedRtpFileReader : public RtpFileReaderImpl {
|
||||
public:
|
||||
~InterleavedRtpFileReader() override {
|
||||
if (file_ != NULL) {
|
||||
if (file_ != nullptr) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Init(const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) override {
|
||||
file_ = fopen(filename.c_str(), "rb");
|
||||
if (file_ == NULL) {
|
||||
printf("ERROR: Can't open file: %s\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
|
||||
file_ = file;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NextPacket(RtpPacket* packet) override {
|
||||
assert(file_ != NULL);
|
||||
assert(file_ != nullptr);
|
||||
packet->length = RtpPacket::kMaxPacketBufferSize;
|
||||
uint32_t len = 0;
|
||||
TRY(ReadUint32(&len, file_));
|
||||
@ -107,7 +102,7 @@ class InterleavedRtpFileReader : public RtpFileReaderImpl {
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* file_ = NULL;
|
||||
FILE* file_ = nullptr;
|
||||
int64_t time_ms_ = 0;
|
||||
};
|
||||
|
||||
@ -115,24 +110,19 @@ class InterleavedRtpFileReader : public RtpFileReaderImpl {
|
||||
// http://www.cs.columbia.edu/irt/software/rtptools/
|
||||
class RtpDumpReader : public RtpFileReaderImpl {
|
||||
public:
|
||||
RtpDumpReader() : file_(NULL) {}
|
||||
RtpDumpReader() : file_(nullptr) {}
|
||||
~RtpDumpReader() override {
|
||||
if (file_ != NULL) {
|
||||
if (file_ != nullptr) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Init(const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) override {
|
||||
file_ = fopen(filename.c_str(), "rb");
|
||||
if (file_ == NULL) {
|
||||
printf("ERROR: Can't open file: %s\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
|
||||
file_ = file;
|
||||
|
||||
char firstline[kFirstLineLength + 1] = {0};
|
||||
if (fgets(firstline, kFirstLineLength, file_) == NULL) {
|
||||
if (fgets(firstline, kFirstLineLength, file_) == nullptr) {
|
||||
RTC_LOG(LS_INFO) << "Can't read from file";
|
||||
return false;
|
||||
}
|
||||
@ -179,10 +169,11 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
||||
// Use 'len' here because a 'plen' of 0 specifies rtcp.
|
||||
len -= kPacketHeaderSize;
|
||||
if (packet->length < len) {
|
||||
FATAL() << "Packet is too large to fit: " << len << " bytes vs "
|
||||
<< packet->length
|
||||
<< " bytes allocated. Consider increasing the buffer "
|
||||
"size";
|
||||
RTC_LOG(LS_ERROR) << "Packet is too large to fit: " << len << " bytes vs "
|
||||
<< packet->length
|
||||
<< " bytes allocated. Consider increasing the buffer "
|
||||
"size";
|
||||
return false;
|
||||
}
|
||||
if (fread(rtp_data, 1, len, file_) != len) {
|
||||
return false;
|
||||
@ -242,7 +233,7 @@ const uint32_t kPcapBOMNoSwapOrder = 0xa1b2c3d4UL;
|
||||
class PcapReader : public RtpFileReaderImpl {
|
||||
public:
|
||||
PcapReader()
|
||||
: file_(NULL),
|
||||
: file_(nullptr),
|
||||
swap_pcap_byte_order_(false),
|
||||
#ifdef WEBRTC_ARCH_BIG_ENDIAN
|
||||
swap_network_byte_order_(false),
|
||||
@ -256,24 +247,18 @@ class PcapReader : public RtpFileReaderImpl {
|
||||
}
|
||||
|
||||
~PcapReader() override {
|
||||
if (file_ != NULL) {
|
||||
if (file_ != nullptr) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Init(const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) override {
|
||||
return Initialize(filename, ssrc_filter) == kResultSuccess;
|
||||
bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
|
||||
return Initialize(file, ssrc_filter) == kResultSuccess;
|
||||
}
|
||||
|
||||
int Initialize(const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) {
|
||||
file_ = fopen(filename.c_str(), "rb");
|
||||
if (file_ == NULL) {
|
||||
printf("ERROR: Can't open file: %s\n", filename.c_str());
|
||||
return kResultFail;
|
||||
}
|
||||
int Initialize(FILE* file, const std::set<uint32_t>& ssrc_filter) {
|
||||
file_ = file;
|
||||
|
||||
if (ReadGlobalHeader() < 0) {
|
||||
return kResultFail;
|
||||
@ -637,24 +622,59 @@ class PcapReader : public RtpFileReaderImpl {
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(PcapReader);
|
||||
};
|
||||
|
||||
RtpFileReader* RtpFileReader::Create(FileFormat format,
|
||||
const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) {
|
||||
RtpFileReaderImpl* reader = NULL;
|
||||
RtpFileReaderImpl* CreateReaderForFormat(RtpFileReader::FileFormat format) {
|
||||
RtpFileReaderImpl* reader = nullptr;
|
||||
switch (format) {
|
||||
case kPcap:
|
||||
case RtpFileReader::kPcap:
|
||||
reader = new PcapReader();
|
||||
break;
|
||||
case kRtpDump:
|
||||
case RtpFileReader::kRtpDump:
|
||||
reader = new RtpDumpReader();
|
||||
break;
|
||||
case kLengthPacketInterleaved:
|
||||
case RtpFileReader::kLengthPacketInterleaved:
|
||||
reader = new InterleavedRtpFileReader();
|
||||
break;
|
||||
}
|
||||
if (!reader->Init(filename, ssrc_filter)) {
|
||||
return reader;
|
||||
}
|
||||
|
||||
RtpFileReader* RtpFileReader::Create(FileFormat format,
|
||||
const uint8_t* data,
|
||||
size_t size,
|
||||
const std::set<uint32_t>& ssrc_filter) {
|
||||
std::unique_ptr<RtpFileReaderImpl> reader(CreateReaderForFormat(format));
|
||||
|
||||
FILE* file = tmpfile();
|
||||
if (file == nullptr) {
|
||||
printf("ERROR: Can't open file from memory buffer\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fwrite(reinterpret_cast<const void*>(data), sizeof(uint8_t), size,
|
||||
file) != size) {
|
||||
return nullptr;
|
||||
}
|
||||
rewind(file);
|
||||
|
||||
if (!reader->Init(file, ssrc_filter)) {
|
||||
return nullptr;
|
||||
}
|
||||
return reader.release();
|
||||
}
|
||||
|
||||
RtpFileReader* RtpFileReader::Create(FileFormat format,
|
||||
const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter) {
|
||||
RtpFileReaderImpl* reader = CreateReaderForFormat(format);
|
||||
FILE* file = fopen(filename.c_str(), "rb");
|
||||
if (file == nullptr) {
|
||||
printf("ERROR: Can't open file: %s\n", filename.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!reader->Init(file, ssrc_filter)) {
|
||||
delete reader;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
@ -34,11 +34,14 @@ class RtpFileReader {
|
||||
enum FileFormat { kPcap, kRtpDump, kLengthPacketInterleaved };
|
||||
|
||||
virtual ~RtpFileReader() {}
|
||||
static RtpFileReader* Create(FileFormat format,
|
||||
const uint8_t* data,
|
||||
size_t size,
|
||||
const std::set<uint32_t>& ssrc_filter);
|
||||
static RtpFileReader* Create(FileFormat format, const std::string& filename);
|
||||
static RtpFileReader* Create(FileFormat format,
|
||||
const std::string& filename,
|
||||
const std::set<uint32_t>& ssrc_filter);
|
||||
|
||||
virtual bool NextPacket(RtpPacket* packet) = 0;
|
||||
};
|
||||
} // namespace test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user