New parser for event log. Manually parse the outermost EventStream to more easily deal with corrupt or partially written logs.
Changed rtpdump converter and neteq tool to use new parser, but still aborting if the file is corrupt. Review-Url: https://codereview.webrtc.org/1768773002 Cr-Commit-Position: refs/heads/master@{#12714}
This commit is contained in:
@ -16,51 +16,15 @@
|
||||
#include <limits>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/call.h"
|
||||
#include "webrtc/call/rtc_event_log.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
|
||||
// Files generated at build-time by the protobuf compiler.
|
||||
#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
|
||||
#include "external/webrtc/webrtc/call/rtc_event_log.pb.h"
|
||||
#else
|
||||
#include "webrtc/call/rtc_event_log.pb.h"
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
const rtclog::RtpPacket* GetRtpPacket(const rtclog::Event& event) {
|
||||
if (!event.has_type() || event.type() != rtclog::Event::RTP_EVENT)
|
||||
return nullptr;
|
||||
if (!event.has_timestamp_us() || !event.has_rtp_packet())
|
||||
return nullptr;
|
||||
const rtclog::RtpPacket& rtp_packet = event.rtp_packet();
|
||||
if (!rtp_packet.has_type() || rtp_packet.type() != rtclog::AUDIO ||
|
||||
!rtp_packet.has_incoming() || !rtp_packet.incoming() ||
|
||||
!rtp_packet.has_packet_length() || rtp_packet.packet_length() == 0 ||
|
||||
!rtp_packet.has_header() || rtp_packet.header().size() == 0 ||
|
||||
rtp_packet.packet_length() < rtp_packet.header().size())
|
||||
return nullptr;
|
||||
return &rtp_packet;
|
||||
}
|
||||
|
||||
const rtclog::AudioPlayoutEvent* GetAudioPlayoutEvent(
|
||||
const rtclog::Event& event) {
|
||||
if (!event.has_type() || event.type() != rtclog::Event::AUDIO_PLAYOUT_EVENT)
|
||||
return nullptr;
|
||||
if (!event.has_timestamp_us() || !event.has_audio_playout_event())
|
||||
return nullptr;
|
||||
const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event();
|
||||
if (!playout_event.has_local_ssrc())
|
||||
return nullptr;
|
||||
return &playout_event;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RtcEventLogSource* RtcEventLogSource::Create(const std::string& file_name) {
|
||||
RtcEventLogSource* source = new RtcEventLogSource();
|
||||
RTC_CHECK(source->OpenFile(file_name));
|
||||
@ -76,42 +40,57 @@ bool RtcEventLogSource::RegisterRtpHeaderExtension(RTPExtensionType type,
|
||||
}
|
||||
|
||||
Packet* RtcEventLogSource::NextPacket() {
|
||||
while (rtp_packet_index_ < event_log_->stream_size()) {
|
||||
const rtclog::Event& event = event_log_->stream(rtp_packet_index_);
|
||||
const rtclog::RtpPacket* rtp_packet = GetRtpPacket(event);
|
||||
rtp_packet_index_++;
|
||||
if (rtp_packet) {
|
||||
uint8_t* packet_header = new uint8_t[rtp_packet->header().size()];
|
||||
memcpy(packet_header, rtp_packet->header().data(),
|
||||
rtp_packet->header().size());
|
||||
Packet* packet = new Packet(packet_header, rtp_packet->header().size(),
|
||||
rtp_packet->packet_length(),
|
||||
event.timestamp_us() / 1000, *parser_.get());
|
||||
if (packet->valid_header()) {
|
||||
// Check if the packet should not be filtered out.
|
||||
if (!filter_.test(packet->header().payloadType) &&
|
||||
!(use_ssrc_filter_ && packet->header().ssrc != ssrc_))
|
||||
return packet;
|
||||
} else {
|
||||
std::cout << "Warning: Packet with index " << (rtp_packet_index_ - 1)
|
||||
<< " has an invalid header and will be ignored." << std::endl;
|
||||
while (rtp_packet_index_ < parsed_stream_.GetNumberOfEvents()) {
|
||||
if (parsed_stream_.GetEventType(rtp_packet_index_) ==
|
||||
ParsedRtcEventLog::RTP_EVENT) {
|
||||
PacketDirection direction;
|
||||
MediaType media_type;
|
||||
size_t header_length;
|
||||
size_t packet_length;
|
||||
uint64_t timestamp_us = parsed_stream_.GetTimestamp(rtp_packet_index_);
|
||||
parsed_stream_.GetRtpHeader(rtp_packet_index_, &direction, &media_type,
|
||||
nullptr, &header_length, &packet_length);
|
||||
if (direction == kIncomingPacket && media_type == MediaType::AUDIO) {
|
||||
uint8_t* packet_header = new uint8_t[header_length];
|
||||
parsed_stream_.GetRtpHeader(rtp_packet_index_, nullptr, nullptr,
|
||||
packet_header, nullptr, nullptr);
|
||||
Packet* packet = new Packet(packet_header, header_length, packet_length,
|
||||
static_cast<double>(timestamp_us) / 1000,
|
||||
*parser_.get());
|
||||
if (packet->valid_header()) {
|
||||
// Check if the packet should not be filtered out.
|
||||
if (!filter_.test(packet->header().payloadType) &&
|
||||
!(use_ssrc_filter_ && packet->header().ssrc != ssrc_)) {
|
||||
rtp_packet_index_++;
|
||||
return packet;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Warning: Packet with index " << rtp_packet_index_
|
||||
<< " has an invalid header and will be ignored."
|
||||
<< std::endl;
|
||||
}
|
||||
// The packet has either an invalid header or needs to be filtered out,
|
||||
// so it can be deleted.
|
||||
delete packet;
|
||||
}
|
||||
// The packet has either an invalid header or needs to be filtered out, so
|
||||
// it can be deleted.
|
||||
delete packet;
|
||||
}
|
||||
rtp_packet_index_++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int64_t RtcEventLogSource::NextAudioOutputEventMs() {
|
||||
while (audio_output_index_ < event_log_->stream_size()) {
|
||||
const rtclog::Event& event = event_log_->stream(audio_output_index_);
|
||||
const rtclog::AudioPlayoutEvent* playout_event =
|
||||
GetAudioPlayoutEvent(event);
|
||||
while (audio_output_index_ < parsed_stream_.GetNumberOfEvents()) {
|
||||
if (parsed_stream_.GetEventType(audio_output_index_) ==
|
||||
ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) {
|
||||
uint64_t timestamp_us = parsed_stream_.GetTimestamp(audio_output_index_);
|
||||
// We call GetAudioPlayout only to check that the protobuf event is
|
||||
// well-formed.
|
||||
parsed_stream_.GetAudioPlayout(audio_output_index_, nullptr);
|
||||
audio_output_index_++;
|
||||
return timestamp_us / 1000;
|
||||
}
|
||||
audio_output_index_++;
|
||||
if (playout_event)
|
||||
return event.timestamp_us() / 1000;
|
||||
}
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
@ -120,8 +99,7 @@ RtcEventLogSource::RtcEventLogSource()
|
||||
: PacketSource(), parser_(RtpHeaderParser::Create()) {}
|
||||
|
||||
bool RtcEventLogSource::OpenFile(const std::string& file_name) {
|
||||
event_log_.reset(new rtclog::EventStream());
|
||||
return RtcEventLog::ParseRtcEventLog(file_name, event_log_.get());
|
||||
return parsed_stream_.ParseFile(file_name);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/call/rtc_event_log_parser.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/tools/packet_source.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
|
||||
@ -22,10 +23,6 @@ namespace webrtc {
|
||||
|
||||
class RtpHeaderParser;
|
||||
|
||||
namespace rtclog {
|
||||
class EventStream;
|
||||
} // namespace rtclog
|
||||
|
||||
namespace test {
|
||||
|
||||
class Packet;
|
||||
@ -55,10 +52,10 @@ class RtcEventLogSource : public PacketSource {
|
||||
|
||||
bool OpenFile(const std::string& file_name);
|
||||
|
||||
int rtp_packet_index_ = 0;
|
||||
int audio_output_index_ = 0;
|
||||
size_t rtp_packet_index_ = 0;
|
||||
size_t audio_output_index_ = 0;
|
||||
|
||||
std::unique_ptr<rtclog::EventStream> event_log_;
|
||||
ParsedRtcEventLog parsed_stream_;
|
||||
std::unique_ptr<RtpHeaderParser> parser_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RtcEventLogSource);
|
||||
|
||||
Reference in New Issue
Block a user